├── .DS_Store
├── .gitignore
├── LICENSE
├── README.md
├── demo_code
├── LuotuoFighter.txt
├── edge_data_2.txt
├── gradio_baichuan.ipynb
├── node_data_2.txt
└── print_DND_fighter_baichuan.ipynb
└── figures
├── .DS_Store
├── BattleExample.jpg
├── BattleExample.pptx
├── BattleLogs.jpg
├── BattleLogs.pptx
├── FeatureList.jpg
├── FeatureList.pptx
├── Hit_Damage_Relationship.png
├── LifeReloaded.jpg
├── RPG-script_with_image
├── 冰原巨人.pptx
├── 北方食人妖.pptx
├── 山地巨人.pptx
├── 神圣武士泰尔.pptx
└── 黑暗精灵.pptx
├── YingXiong.png
├── character_earth.jpeg
├── character_fire.jpeg
├── character_water.jpeg
├── dmg_per_hp.png
├── level_selection.jpeg
└── xiuxian.jpeg
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/.DS_Store
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # pdm
105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106 | #pdm.lock
107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108 | # in version control.
109 | # https://pdm.fming.dev/#use-with-ide
110 | .pdm.toml
111 |
112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113 | __pypackages__/
114 |
115 | # Celery stuff
116 | celerybeat-schedule
117 | celerybeat.pid
118 |
119 | # SageMath parsed files
120 | *.sage.py
121 |
122 | # Environments
123 | .env
124 | .venv
125 | env/
126 | venv/
127 | ENV/
128 | env.bak/
129 | venv.bak/
130 |
131 | # Spyder project settings
132 | .spyderproject
133 | .spyproject
134 |
135 | # Rope project settings
136 | .ropeproject
137 |
138 | # mkdocs documentation
139 | /site
140 |
141 | # mypy
142 | .mypy_cache/
143 | .dmypy.json
144 | dmypy.json
145 |
146 | # Pyre type checker
147 | .pyre/
148 |
149 | # pytype static type analyzer
150 | .pytype/
151 |
152 | # Cython debug symbols
153 | cython_debug/
154 |
155 | # PyCharm
156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158 | # and can be added to the global gitignore or merged into this file. For a more nuclear
159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160 | #.idea/
161 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 骆驼大乱斗
2 | # Luotuo-Fighter: Massive Game Content Generated by LLM
3 |
4 | 百川期间天梯临时链接 https://luotuo.sirly.cc/
5 |
6 | []()
7 | []()
8 | [](https://huggingface.co/spaces/silk-road/Luotuo-Fighter-GO)
9 |
10 | **骆驼大乱斗**是使用语言模型生成游戏内容的战斗文字游戏。
11 |
12 | 骆驼大乱斗初步在百川Hackathon期间搭建,包括初步的战斗引擎和简单的关卡成长系统。后续会继续完善。骆驼大乱斗的核心思路,是仅在关卡创建或者角色创建的时候,使用语言模型生成大量的游戏内容,而后则尽可能去使用状态机逻辑进行运行。
13 |
14 |
15 |
16 |
17 |
18 |
19 | 预计在百川Hackathon期间我们会初步完成骆驼大乱斗的战斗引擎部分。伴随着这个战斗引擎,我们还会做一个自动生成关卡,带有属性成长性质MiniRPG。
20 |
21 | 同时如果有时间,我们后面再利用LuotuoFighter的战斗引擎去做一个门派经营模拟类的游戏。
22 |
23 | StoryTeller是做到一半的原计划,可以实现一些剧情的尝试和游戏。
24 |
25 |
26 | ## 快速开始
27 |
28 | 可以直接尝试运行以下的colab链接启动项目或者Hugging Face Demo来进行体验
29 |
30 |
31 | | 名称 |colab链接| 说明 |
32 | |---|---|---|
33 | |骆驼大乱斗天梯| [临时链接](https://luotuo.sirly.cc/) | 百川期间的链接,现场前5+名我们请喝奶茶 |
34 | |骆驼大乱斗天梯| [](https://huggingface.co/spaces/silk-road/Luotuo-Fighter-GO) | 百川备用链接,现场前5+名我们请喝奶茶 |
35 | |骆驼大乱斗-魔搭 | [🤖魔搭](https://modelscope.cn/studios/Jyshen/Luotuo-Fighter-GO/summary) | 百川期间魔搭的版本 |
36 | |骆驼大乱斗HF | [](https://huggingface.co/spaces/silk-road/Luotuo-Fighter-GO) | 骆驼大乱斗,仅包含战斗引擎和天梯 |
37 | |骆驼RPG | | 一个带上数值成长的RPG版本 |
38 | |骆驼RPG-HF | | RPG版本的Hugging Face Demo |
39 | |关卡生成 | | 用于生成骆驼RPG的关卡的prompt |
40 | |人物生成 | | 一个简易的人物生成代码,已经集成在大乱斗中 |
41 | |战斗视频| [B站链接](https://www.bilibili.com/video/BV1SN41147ae/) | 用DALLE3补全战斗画面后生成的视频 |
42 |
43 | ## 百川期间天梯规则
44 |
45 | + 点击百川期间天梯的链接(或者备用链接)。尽量使用自己的姓名生成人物
46 |
47 | + 生成人物后可以参与天梯对战,多选几个人随机对战,提升天梯排名
48 |
49 | + 需要和我们说一下这个姓名是你生成的。如果有重名,尽量使用网名
50 |
51 | + 一个名字可以被不同的描述多次生成,天梯对战的时候会自动取Elo战力高的。
52 |
53 | + 截止路演那一天 max(5, 现场参与人数*20%) 我们会请奶茶 所以哪个人物是你生成的一定要和我们说一下我们会记录的 不然到时候找不到人发奶茶 (精确的截止日期按照我们slides提交,也就是路演前一天晚上来算)
54 |
55 | Just for Fun
56 |
57 |
58 | # 效果展示
59 |
60 |
61 |
62 |
63 |
64 | 战斗描述由骆驼大乱斗生成,战斗画面需要用户自行脑补。或者输入DALLE3进行生成。
65 |
66 | ## 一个简单的战斗的例子
67 |
68 | ## 骆驼RPG的展示
69 |
70 | ## TODO List
71 |
72 | - [ ] 发布Gradio版本的骆驼大乱斗colab
73 | - [ ] 骆驼大乱斗部署到Hugging Face
74 | - [ ] 骆驼大乱斗-RPG Print版本
75 | - [ ] 发布简单的角色生成和关卡生成的代码
76 | - [ ] 增加躲避、招架的文本描述
77 | - [ ] 增加伤害结算文字化的描述
78 | - [ ] 增加流血、中毒等异常状态,为招式增加异常状态附着比例
79 | - [ ] 增加一个全局的胜率统计系统
80 |
81 | ---
82 |
83 | # 骆驼大乱斗的tech report:
84 | # Luotuo-Fighter: Massive Game Content Generated by LLM
85 |
86 | # 引言
87 |
88 | 随着2023年前后语言模型的蓬勃发展,尤其是ChatGPT, Stanford的Generative Agents,以及OpenAI的Code Interpreter发布之后,语言模型在游戏生成的潜力受到很大的关注。
89 |
90 | 然而,使用语言模型来代替游戏中的状态机运行,或者是利用语言模型推动游戏的Agents行为,有一定的缺陷。首先,运行语言模型,无论是使用API的方式还是使用本地模型的方式,都有较高的成本。其次,较高的计算资源占用的同时,语言模型的反应速度也慢于传统的基于状态机的游戏形式。最后,语言模型还会遇到输出不稳定的情况。
91 |
92 | 所以,在本项目中,我们使用了另一种思路,我们希望在一个规定的框架下,利用语言模型去大量生成游戏中的关键内容。包括技能、关卡和一部分数值的设计。
93 |
94 | 本项目的主要贡献如下:
95 |
96 | 1、我们建立了一套PVP的战斗引擎。并且玩家可以使用语言模型,批量生成战斗中的人物和技能。并且我们提出的系统,可以根据用户的姓名和对于角色的描述,生成复合用户期望的角色。
97 |
98 | 2、在确定了战斗引擎的超参数后,我们建立了一套关卡创建系统,这套系统可以根据游戏开发者的需求,创建结构化的关卡游戏数据。结合之前提到的战斗引擎,形成一个大多数要素都是由AI生成的,成长型的战斗游戏。
99 |
100 | 3、在百川黑客松中,我们预期会完成骆驼Fighter战斗系统,并且提供一个天梯系统,对玩家创建的人物进行排名。同时骆驼Fighter和骆驼RPG的代码都会在 https://github.com/LC1332/Luotuo-Fighter 中发布。
101 |
102 |
103 | # 相关游戏
104 |
105 |
106 | + **姓名大作战** 姓名大作战可以看成非常早期的AIGC游戏。姓名大作战中使用用户输入姓名的base64编码,结合随机数对用户指定姓名的角色进行生成。不过姓名大作战没有平衡性的设计。在骆驼大乱斗的尝试中,我们也希望人物的生成能够简化到用户输入姓名和角色描述,就能够对角色进行完整的生成。所以也可以将骆驼大乱斗看成是姓名大作战的自然语言模型生成版本。
107 |
108 | + **Pokemon** 作为一个经典的,拥有各地区锦标赛的游戏。神奇宝贝对战拥有较好的平衡性。在伤害和命中设计中,我们参考了神奇宝贝的伤害计算公式,并进行了一定的修改。
109 |
110 | + **白金英雄坛说** 白金英雄坛说是一个非常早期,运行在文曲星平台上的文字对战游戏。我们的骆驼大乱斗参考了白金英雄坛说的文字输出型。
111 |
112 | + **人生重开模拟器** 人生重开模拟器是2021年流行过的一个文字游戏。这个游戏给了一个最简单的状态机事件的例子,并且在2021年获得了广泛的关注。
113 |
114 | + **LifeReloaded( Code Interpreter )** 在OpenAI发布Code Interpreter之后,有包括陈财猫等不同的group开始研究使用Code Interpreter进行语言模型进行人生重开模拟的尝试 https://github.com/EmbraceAGI/LifeReloaded 。本项目借鉴了这里的一部分prompt。另一方面,我们希望使用更好的数值模拟的方式,来解决游玩这个游戏的时候数值发散的问题,以及使用生成内容载入到传统游戏框架,来成倍降低AIGC游戏的运行成本。
115 |
116 | # 战斗机制设计
117 |
118 | ## 人物属性
119 |
120 | 在目前的骆驼大乱斗版本中,有三个最简单的属性。力量STR,体质VIT和敏捷SPD。力量关系到人物的伤害。VIT关系到人物的血量和防御,敏捷关系到人物的出手顺序和命中率。在这里我们希望人物在各个属性的加点的期望收益是类似的,我们先介绍伤害和命中率公式的设计,再介绍如何通过一个简单的实验,来平衡三个属性的收益。
121 |
122 | ## 伤害计算
123 |
124 | 假设技能本身的伤害为 $SkillDamage$ , 攻击者的力量为 $STR_1$ ,被攻击者的体质为 $VIT_2$。
125 |
126 | 那么技能伤害本身的产生的基础伤害为
127 |
128 | $$ D_0 = STR_1 * STRStrength + SkillDamage $$
129 |
130 | 这个伤害会随着进攻方的力量呈现一定的增长,其中$STRStrength$为2。同时,伤害会随着进攻者的攻击力和防御者的防御力的差距发生正负25%的浮动。
131 |
132 | $$ D = D_0 * ( 1 + 0.5 * (1/( \textup{exp}(-(STR_1 - VITDecayRatio *VIT_2)/6.0) ) - 0.5 ) ) $$
133 |
134 | 因为角色的血量已经会随着 $VIT$ 的数值线性增长,所以需要用 $VITDecayRatio$ 去削弱 $VIT$ 的效果,这里 $VITDecayRatio$ 取0.5。
135 |
136 | ## 命中率计算
137 |
138 | 每个招式会有一个招式本身的命中率 $SkillHit$
139 |
140 | 命中率会受到进攻者的速度 $SPD_1$和被攻击者的速度 $SPD_2$ 的影响。实际的命中率为
141 |
142 | $$ H = SkillHit +\textup{max}(30, SkillHit) * (-0.5 + 1.0 / (1.0 +\textup{exp}(- (SPD_1 - SPD_2) / 6.0)) )/2.0 ) $$
143 |
144 | 命中率会受到两者的速度差,产生正负25%的影响。
145 |
146 |
147 | ## 各个系数的确定
148 |
149 | 我们希望游戏中角色的 $STR$, $VIT$ 和 $SPD$ 处在相对平衡的位置。这里我们研究角色一次攻击,对被攻击者血量的百分比影响,即研究
150 |
151 | $$ R = \textup{min}(100,H) * D / HP_2 $$
152 |
153 | 和三个属性之间的关系。
154 |
155 | 在这里我们规定了角色每个维度的值为0-20之间的整数,并且将角色的三个维度之和选取在30。
156 |
157 | 我们根据这个规则生成了40个不同的角色,并且让这些角色相互之间使用一个标准威力为50的招式进行相互攻击,并且统计单词攻击对对方血量造成的伤害百分比。
158 |
159 |
160 |
161 |
162 |
163 | 这里因为角色的血量为
164 |
165 | $$ HP_a * (VIT + HP_b) $$
166 |
167 | 我们可以通过调整下面这些系数,来平衡 $STR$ , $SPD$ 和 $VIT$ 之间的影响
168 |
169 | |属性|正向调整|负向调整|
170 | |---|---|---|
171 | |$STR$| $STRStrength$ , 伤害Logistic乘数 | - |
172 | |$VIT$| 伤害Logistic乘数 | $HP_b$ , $VITDecayRatio$ |
173 | |$SPD$| 命中率乘数 | $HP_a$ |
174 |
175 | 通过简易的调整后,我们基本确定了战斗系统中的超参数。命中率乘数和伤害Logistic乘数都为0.5。$HP_b$ 选为10。这个时候期望伤害百分比关于STR和VIT的斜率都接近。
176 |
177 | 速度的收益影响比较复杂,因为速度更快的角色可以先手攻击。所以这里我们接受了上图中各个速度对于对手的伤害期望都接近这个现象。
178 |
179 | ## 技能伤害和命中率之间的关系
180 |
181 | 在Pokemon中,伤害较高的技能,会拥有相对更低的命中率。所以在骆驼大乱斗中,我们也使用命中率去平衡技能的伤害。我们进一步模拟了不同的伤害和命中率组合的情况。
182 |
183 |
184 |
185 |
186 |
187 |
188 | 这个图给出了Hit-Damage的热图,这里为了方便可视化,我们把数值转化了到期望扣血=14%的距离。可以看到在给定一个扣血比例下,我们可以找到一条伤害-命中率的等高线。在实际的骆驼大乱斗中,我们也使用总期望相同的招式伤害-damage组合。
189 |
190 | 需要说明的是,我们这里尽可能平衡了属性和技能伤害的数值,但是我们并没有进一步去搜索在这一设定下人物属性和技能的最优组合,比如非常容易想到的是,玩家可以创建速度较高的角色,使用更高伤害的技能,利用速度值来弥补命中率的缺陷。或者建立一个高攻高防但是速度较低的角色,使用更容易命中的技能。或者取一些中间的状态,这些应该都是可行的。
191 |
192 | 当然,在后续的版本中,我们还希望招式能够附带上一定小概率的流血、破甲、中毒等特殊状态,不论是Pokemon还是姓名大作战,都有这些特殊状态的设计,来进一步增加游戏性。并且一个更好的游戏系统,应该对各个参数和胜率之间的影响进行统计,从而动态去调整各个参数的收益,产生一个更为平衡的AIGC的游戏。这些都可以在后续的研究中进行探索。
193 |
194 | # 利用语言模型生成人物
195 |
196 | 在拥有基础的战斗系统之后,本项目的关键是玩家有较高的自由度去设计或者创建属于自己的人物。我们希望玩家可以用简单的形式,即只输入姓名和简单的描述,就创建出一个人物。同时,如果玩家对人物的细节有更高的要求,也可以在描述中给出更详细的内容。
197 |
198 | ## 根据人物描述生成详细的技能
199 |
200 | 在骆驼大乱斗中,我们希望玩家可以用一个姓名和一个最简单的描述就能够创建人物。所以我们首先使用这样的prompt来对玩家的描述进行扩写
201 |
202 | ```js
203 | 我的名字叫“{Role_Name}”,假设我是一个武侠中的游戏角色,{Description}。请基于我的名字和门派,先为我设计2套武功和一套身法或者招架。
204 |
205 | 再为每套武功设计4个对应招式的名字。
206 | ```
207 |
208 | 在这里语言模型会根据玩家的名字和描述,进一步生成更详细的角色描述。同时会确定角色每个武功中4个招法的名字,下面是这个prompt输出的一个例子
209 |
210 | ```python
211 | role_name = "黄蓉"
212 | description = "丐帮帮主黄蓉,擅长打狗棒法和落英神剑掌,身法为逍遥游。"
213 | ```
214 |
215 | 这个时候ChatGPT的输出为
216 |
217 | ```
218 | 作为丐帮帮主黄蓉,您擅长打狗棒法和落英神剑掌,身法为逍遥游。以下是为您设计的两套武功和一套身法(招架):
219 |
220 | 套路一:打狗棒法
221 | - 武功一:打狗棒法是丐帮的绝技,以棒法为主要攻击手段,威力巨大,灵活多变。
222 | - 武功二:落英神剑掌是黄蓉自创的剑掌技法,结合了剑法和掌法的特点,攻守兼备。
223 | - 身法/招架:逍遥游是黄蓉独特的身法,轻盈灵动,能够迅速躲避敌人的攻击。
224 |
225 | 套路二:落英神剑掌
226 | - 武功一:落英神剑掌是黄蓉的拿手绝技,以剑掌相结合,攻击迅猛而准确。
227 | - 武功二:打狗棒法是黄蓉在丐帮学习的棒法,以棒为主要武器,威力强大。
228 | - 身法/招架:逍遥游是黄蓉的身法,轻灵敏捷,能够迅速躲避敌人的攻击。
229 |
230 | 以下是每套武功对应的四个招式的名字:
231 |
232 | 套路一:打狗棒法
233 | 1. 狗啸山林:以棒法挥舞如狗啸声,迅猛有力,攻敌要害。
234 | 2. 棒影重重:以迅猛的棒影覆盖敌人,让对手难以躲避。
235 | 3. 狗尾续貂:以迅捷的棒法攻击对手的下盘,削弱其防守。
236 | 4. 狗急跳墙:以快速的棒法攻势,迫使对手无处可逃。
237 |
238 | 套路二:落英神剑掌
239 | 1. 落英如雨:以掌法如落英般飘逸,攻敌时如雨点般密集。
240 | 2. 神剑破空:以剑掌相结合,剑气激荡,破空而出,攻敌要害。
241 | 3. 飞花流水:以灵动的剑掌连绵不断,如水中飞舞的花瓣。
242 | 4. 剑指苍穹:以剑掌合一,指向天空,释放出强大的攻击力。
243 |
244 | 请注意,以上是根据您的名字和门派进行的设计,如有需要,您可以根据角色的特点和背景进行进一步的调整和发挥。
245 | ```
246 |
247 | 当然,因为ChatGPT的训练数据中,对中文武侠数据不是很熟悉。在这次百川比赛中,我们也会尝试一下在这一步使用百川来生成看看。另外在这一步中,我们允许语言模型使用非结构化的输出,这样可以把模型的生成温度调高,使得模型产生更多样化的生成结果。
248 |
249 | ## 根据人物描述总结成格式化数据
250 |
251 |
252 | 在让语言模型进行"发散性思维",生成多样化的详细描述之后,我们希望语言模型可以进一步把详细描述,转化为游戏中可以载入的结构化数据。
253 |
254 | ```js
255 | 我正在为我的武侠游戏设计人物。给定一个人物和这个人物的背景描述(可选)
256 |
257 | 我希望你根据这个人物的背景和名字,为我生成这个人的资料,以json的格式输出,包括
258 |
259 | description: 这个角色的背景等信息
260 | weapon: 这个人使用的武器种类,
261 | major_martial_art: 这个人的主要武学
262 | major_movements: 这个人主要武学的4个对应招式的名字。招式的名字需要尽可能和major_martial_art有关。movements的名字尽量不要使用重复的文字。可以使用形象的动作或者是一些动物的比喻。
263 | secondary_movements: 这个角色的次要武学
264 | secondary_movements: 这个人次要武学的4个对应招式的名字。招式的名字需要尽可能和secondary_movements有关
265 | footwork_and_body_method: 这个角色的轻功或者防御功法
266 |
267 | example_input:
268 | name: 令狐冲
269 | description: -
270 | suggestion:-
271 |
272 | example_output:
273 | {
274 | "name": "令狐冲",
275 | "description": "华山派的大师兄",
276 | "weapon": "剑",
277 | "major_martial_art": "独孤九剑",
278 | "major_movements": ["独孤九剑破剑式","独孤九剑总诀式","独孤九剑破气式","独孤九剑破刀式"],
279 | "major_damage": 70,
280 | "secondary_martial_art": "华山剑法",
281 | "secondary_movements": ["有凤来仪","飞沙走石","百丈飞瀑","青山隐隐"],
282 | "secondary_damage":80,
283 | "footwork_and_body_method": "华山身法",
284 | "STR":10,
285 | "VIT":3,
286 | "SPD":20
287 | }
288 |
289 | input:
290 | name:
291 | description:
292 | suggestion:
293 | ```
294 |
295 | 这个时候我们使用one-shot的in-context learning,把之前生成的详细描述转化为角色的属性。由于大多数信息在前一步已经由详细描述生成,在这一步主要负责将之前的非结构化数据转化为结构化的游戏数据。
296 |
297 | ## 根据技能名称实现战斗描述
298 |
299 |
300 |
301 |
302 |
303 |
304 | 为了进一步凸显文字游戏的特性,这里我们希望像文曲星平台的《白金英雄坛说》一样,使用文字去进行招式的描述。所以在这里我们需要将之前生成的招式名字,变为战斗的描述,同时还要考虑招式命中和非命中的情况。
305 |
306 | ```
307 | 现在我希望你根据武侠小说中的武功和招式的名字。为招式补全合理的description和missing描述。
308 | 在description的描述中,player可以击中目标,可以有兵器撞击声响等描述。
309 | 在missing描述中,player并不一定击中目标,不可以有击落、击中、夺去这样的描述
310 | 在用[player]代表技能的使用者,用[target]代表技能的目标。结果需用合理的jsonl格式展示,下面是一个例子。
311 |
312 | example input:
313 | martial_art_name = 华山剑法
314 | {"招式":"百丈飞瀑"}
315 | {"招式":"百鸟朝凤"}
316 | {"招式":"青山隐隐"}
317 | {"招式":"飞沙走石"}
318 |
319 | example output:
320 | {"招式":"百丈飞瀑","description":"[player]翻身回剑,剑诀斜引,一招“百丈飞瀑”,剑锋从半空中直泻下来","missing":"[player]一咬牙,翻身回剑,剑诀斜引,一招“百丈飞瀑”,剑锋从半空中直泻下来"}
321 | {"招式":"百鸟朝凤","description":"[player]长剑一起,使一招“百鸟朝凤”,但见剑尖乱颤,霎时间便如化为数十个剑尖,罩住[target]中盘","missing":"[player]使一招“百鸟朝凤”,但见剑尖乱颤,霎时间便如化为数十个剑尖,向[target]飞去"}
322 | {"招式":"青山隐隐", "description":"[player]吸一口气,长剑中宫直进,剑尖不住颤动,剑到中途,忽然转而向上,乃是一招“青山隐隐”,端的是若有若无,变幻无方。","missing":"[player]吸一口气,长剑中宫直进,剑尖不住颤动,剑到中途,忽然转而向上,乃是一招“青山隐隐”,端的是若有若无,变幻无方。"}
323 | {"招式":"飞沙走石", "description":"长剑挺起,使一招“飞沙走石”,内劲直贯剑尖,寒光点点,挡的一声,击中的[target]胸口。","missing":"长剑挺起,使一招“飞沙走石”,内劲直贯剑尖,寒光点点,直向[target]胸口刺去。"}
324 |
325 |
326 | input:
327 | martial_art_name =
328 | {"招式":""}
329 | {"招式":""}
330 | {"招式":""}
331 | {"招式":""}
332 | ```
333 |
334 | 同样我们发现one-shot的in-context learning可以较好的解决这个问题。由此我们就完成了所有角色描述数据的生成。
335 |
336 | 在百川Hackathon的过程中,我们首先完成了角色攻击数据的生成。身法和招架也可以用近似的道理去完成。
337 |
338 | ## 其他模态的考虑
339 |
340 | 其实原则上来说,一个简易的武侠战斗动画也是可以被生成的,比如可以收集大量的武侠动作的pose轨迹,然后生成一个剪影型的招法动画(类似太吾的战斗效果)。当然黑客松的时间较为有限,这个有空或者有合适数据的时候,可以拿来尝试一下。
341 |
342 | ## 骆驼大乱斗的实践
343 |
344 | 在完成战斗数值和战斗描述的基本系统后,我们已经初步获得一个可以进行玩家角色创建——战斗的系统。在这个前提下,我们在百川Hackathon中上线了一个基础的天梯挑战系统。如果读这篇报告的时候你在百川Hackathon的现场,可以在[快速开始](@快速开始)中找到天梯的链接,在14日晚之前,我们会进行天梯排名,Elo前几名将在15日路演的时候进行奶茶的发放。
345 |
346 |
347 |
348 |
349 |
350 |
351 | 上图展示了几次用户生成的战斗过程。
352 |
353 | # 游戏关卡的自动生成
354 |
355 | 有了基础的战斗系统之后,我们可以考虑在战斗系统中,叠加更多的游戏模式。比较容易想到的是增加一些数值养成的系统,或者去模仿了不起的修仙模拟器(or RimWorld那样),去制作一些养成类的游戏。在百川Hackathon期间,我们先完成了一个带有RPG成长的关卡系统。
356 |
357 | ## 游戏 as 有向图状态机
358 |
359 | 在这里我们参考了一些游戏,包括人生重开模拟器的设计。并且在前期试错的时候我们也尝试了构建人生重开模拟器这样的应用
360 |
361 |
362 |
363 |
364 |
365 | 在类似这样的一个事件推进的游戏中,游戏的状态(除掉玩家属性、道具的部分)可以被描述成一个有向图。每个事件之间可以通过有向图来进行连接。每个事件是一个节点。比如在[这个repo](https://github.com/EwenQuim/renpy-graphviz)中,甚至可以找到可以将Renpy游戏引擎脚本可视化为有向图的代码。
366 |
367 |
368 |
369 |
370 |
371 | 所以在这里,我们也将骆驼大乱斗的RPG版本设计为一个简单的有向图。
372 |
373 |
374 | ## RPG游戏中关卡节点的设计
375 |
376 | 在生成RPG关卡数据的时候,我们先生成节点数据。在节点上,我们会考虑发生战斗,我们把敌人的STR,SPD和VIT的和合并称为一个敌人的战斗力。当一个节点敌人战斗力为0时,则不会发生战斗。并且每个节点会有对应的属性奖励信息。
377 |
378 | 在这里我们使用了较为保守的设计,即每个节点的奖励和战斗力我们是预先设置的。这样可以防止在完全LLM生成游戏中观察到的数值发散的现象。
379 |
380 | ```
381 | 我正在设计一个基于图论的rpg游戏。请为我游戏中的节点补充描述,我游戏中人物的属性只有str, spd和vit(分别代表力量 速度和防御)
382 | 对于节点数据,根据事件名,敌人的战斗力(0表示没有战斗)以及对应的奖励,补充关于这个节点的描述。
383 |
384 | 例子输入:
385 | 节点数据
386 | 序号|事件名|敌人战斗力|奖励|
387 | 1|初始节点|0|-
388 | 2|获取新手装备|0|str+1,spd+1,vit+1
389 |
390 | 例子输出:
391 | 节点数据
392 | 序号|事件名|敌人战斗力|奖励|描述
393 | 1|初始节点|0|-|你转身到了异世界成为勇者,得知了击败魔王的任务
394 | 2|获取新手装备|0|str+1,spd+1,vit+1|村长表示村子里有一些基础的装备,可以使得你的属性获得基本的提升。
395 |
396 | 输入:
397 | 节点数据
398 | 序号|事件名|敌人战斗力|奖励|
399 | 1|初始节点|0|-
400 | 2|力量之路|0|str+1
401 | 3|敏捷之路|0|spd+1
402 | 4|普通力量怪|15|vit+1
403 | 5|普通敏捷怪|15|spd+1
404 | 6|精英力量怪|22|vit+1, str+1
405 | 7|普通敏捷怪|16|spd+1
406 | 8|普通力量怪|23|str+1
407 | 9|精英敏捷怪|25|spd+1, str+1
408 | 10|试炼|28|str+1,spd+1,vit+1
409 | 11|boss守卫|30|str+1,spd+1,vit+1
410 | 12|boss|35|-
411 | ```
412 |
413 | 在这一步的生成中,语言模型会初步生成关卡的描述。这个关卡描述是类似这样的
414 |
415 | ```
416 | 1|初始节点|0|-|你来到了一个神秘的世界,开始了你的冒险之旅
417 | 2|力量之路|0|str+1|你选择了提升力量的道路,在训练中你的力量将得到提升
418 | 3|敏捷之路|0|spd+1|你选择了提升敏捷的道路,在训练中你的速度将得到提升
419 | ```
420 |
421 | 当然,这个关卡描述并不是完全令人满意,在完成边的描述设计之后,我们将会展示怎么将这里的描述进一步anology成特定的风格。
422 |
423 |
424 | ## PRG游戏中边的设计
425 |
426 | 在很多游戏中,都会给予玩家一定的路径选择,比如上古卷轴五中,通过新手山洞之后有力量之石盗贼之石的选择,不同的选择将会将玩家引导到不同的节点,这个时候我们需要为边给出描述。我们使用这个描述,来提供给玩家让玩家进行选择。
427 |
428 | ```
429 | 我正在设计一个基于图论的rpg游戏。我已经完成了游戏中的节点描述
430 |
431 | 请为我进一步补充边信息中,场景转换的信息描述
432 |
433 | 对于边数据,补充这个边是在哪两个节点之间进行了转化,并且补充转换的时候,向用户展示的transition选项的文字描述
434 |
435 | 当同一个节点可以向不同的节点进行转化时,对应的描述应该有所不同。
436 |
437 | 例子输入:
438 | 节点数据
439 | 序号|事件名|敌人战斗力|奖励|描述
440 | 1|初始节点|0|-|你来到了一个神秘的世界,开始了你的冒险之旅
441 | 2|体质之路|0|vit+1|你选择了提升体质的道路,在训练中你的体质将得到提升
442 | 3|敏捷之路|0|spd+1|你选择了提升敏捷的道路,在训练中你的速度将得到提升
443 |
444 |
445 | 边:
446 | Source|Target
447 | 1|2
448 | 1|3
449 |
450 | 例子输出:
451 | Source|Target|Events|Transition
452 | 1|2|初始节点->体质之路|选择体质之路,这条路将帮助你成为一个强壮的骑士
453 | 1|3|初始节点->敏捷之路|选择敏捷之路,如果你偏好盗贼或者刺客,这条路将是你的选择
454 |
455 | 输入:
456 | 节点数据:
457 | 序号|事件名|敌人战斗力|奖励|描述
458 | 1|初入门派|0|-|你踏入江湖,加入了一个门派开始修炼
459 | 2|力量型普通怪|15|str+1|你遇到了一个15战力的力量型普通怪物,通过战胜它你的力量获得了提高
460 | 3|挑战力量型精英怪|20|str+3|你挑战了一个20战力的力量型精英怪物,艰难取胜后你的力量大幅提升
461 | 4|普通怪|16|-|你遇到了一个16战力的普通怪物,它的战斗对你来说并不简单
462 | 5|敏捷型普通怪|17|spd+1|你遇到了一个17战力的敏捷型普通怪物,战胜它你的敏捷得到了提升
463 | 6|敏捷型精英怪|21|spd+3|你挑战了一个21战力的敏捷型精英怪物,取胜后你的敏捷大幅提升
464 | 7|普通怪|18|-|你遇到了一个18战力的普通怪物,需要花费一定力气打败它
465 | 8|体质型普通怪|19|vit+1|你遇到了一个19战力的体质型普通怪物,战胜它你的体质获得提升
466 | 9|体质型精英怪|21|vit+3|你挑战了一个21战力的体质型精英怪物,艰难取胜后你的体质大幅提升
467 | 10|最终的试炼|25|-|这是最后的试炼,只有战胜25战力的怪物才能通过
468 |
469 | 边:
470 | Source|Target
471 | 1|2
472 | 1|3
473 | 2|4
474 | 3|4
475 | 4|5
476 | 4|6
477 | 5|7
478 | 6|7
479 | 7|8
480 | 7|9
481 | 8|10
482 | 9|10
483 | ```
484 |
485 | 在骆驼大乱斗的RPG版本中,边被简化为任何条件都可以转移。而在人生重开模拟器或者博德之门中,边是有一定的附加条件的。比如要求特定的属性维度超过一定的点数。如果想要创造更复杂的节点图像,可能还需要进行更深入的研究。
486 |
487 | ## 将节点和边anology到特定风格的故事中
488 |
489 | 这个时候我们可以使用语言模型的anology能力,将描述转化为特定风格的描述
490 |
491 | ```
492 | 我正在将我的游戏转化为北欧神话风格
493 |
494 | 注意这个表中的描述
495 |
496 | 序号|事件名|敌人战斗力|奖励|描述
497 | 1|初入门派|0|-|你踏入江湖,加入了一个门派开始修炼
498 | 2|力量型普通怪|15|str+1|你遇到了一个15战力的力量型普通怪物,通过战胜它你的力量获得了提高
499 | 3|挑战力量型精英怪|20|str+3|你挑战了一个20战力的力量型精英怪物,艰难取胜后你的力量大幅提升
500 | ...
501 | 9|体质型精英怪|21|vit+3|你挑战了一个21战力的体质型精英怪物,艰难取胜后你的体质大幅提升
502 | 10|最终的试炼|25|-|这是最后的试炼,只有战胜25战力的怪物才能通过
503 |
504 | 我希望描述更接近武侠风格,
505 |
506 | 并且不要使用"普通力量怪"这样直白的名字,而是以"巨狼芬尼尔"这样更北欧神话风格的名字来标记每个敌人
507 |
508 | 将boss改名为某个家族首领的名字。并且保持各个描述之间的风格一致性
509 |
510 | 请根据这些规则为我重新生成这个表格
511 | ```
512 |
513 | 这个方式是非常有效的,这个prompt的输出如下
514 |
515 | ```
516 | 序号|事件名|敌人战斗力|奖励|描述
517 | -|-|-|-|-
518 | 1|踏上英灵殿|0|-|你来到英灵殿,开始了成为英雄的旅程
519 | 2|北方食人妖|15|str+1|北方食人妖芬尼尔持有神秘战斧,如果打败它,你的力量将得到提升
520 | 3|挑战巨龙法夫纳|20|str+3|恶龙法夫纳拥有无穷力量,如果你能打败它,你的力量将大幅提升
521 | ...
522 | 9|神圣武士泰尔|21|vit+3|神圣武士泰尔拥有神力,如果你能战胜他,你的生命力将大幅提升
523 | 10|最后的试炼|25|-|这是成为英雄的最后试炼,只有打败25战力的对手才能通过
524 | ```
525 |
526 | 这个时候我们就可以用转化后的节点和边数据,输入到骆驼大乱斗-RPG中。
527 |
528 | ## 骆驼大乱斗-RPG
529 |
530 | 这里给出骆驼大乱斗-RPG的效果
531 |
532 |
533 | 【等一个图】
534 |
535 |
536 | # 结论
537 |
538 |
539 |
540 | # 附录: 使用的prompt
--------------------------------------------------------------------------------
/demo_code/LuotuoFighter.txt:
--------------------------------------------------------------------------------
1 | {"name": "李鲁鲁", "attr_str": "{\n \"name\": \"李鲁鲁\",\n \"description\": \"山东逍遥派的游戏角色,擅长人工智能傀儡术\",\n \"weapon\": \"智能刀剑\",\n \"major_martial_art\": \"电脑幻影拳法\",\n \"major_movements\": [\"电脑虚像拳\", \"数据掌控击\", \"模拟迷雾拳\", \"程序化拳法\"],\n \"major_damage\": 75,\n \"secondary_martial_art\": \"智能预测刀法\",\n \"secondary_movements\": [\"预测之刃\", \"数据漩涡斩\", \"算法刀舞\", \"智能反击剑\"],\n \"secondary_damage\": 85,\n \"footwork_and_body_method\": \"数码幻影步\",\n \"STR\": 6,\n \"VIT\": 5,\n \"SPD\": 18\n}\n", "skills": "\n{\"招式\":\"电脑虚像拳\",\"description\":\"[player]运用电脑幻影拳法,双拳虚虚实实,制造出多个虚像,令[target]难以分辨真伪,招招不离其身。\",\"missing\":\"[player]运用电脑幻影拳法,双拳虚虚实实,制造出多个虚像,令[target]难以分辨真伪。\"}\n{\"招式\":\"数据掌控击\",\"description\":\"[player]施展数据掌控击,利用数据流动的速度,犹如电光闪烁,快速攻击[target],剑招迅猛,如电一般。\",\"missing\":\"[player]施展数据掌控击,利用数据流动的速度,犹如电光闪烁,快速攻击[target],剑招迅猛。\"}\n{\"招式\":\"模拟迷雾拳\",\"description\":\"[player]施展模拟迷雾拳,释放出模糊幻影,混淆[target]的视线,令其难以辨别攻击方向。\",\"missing\":\"[player]施展模拟迷雾拳,释放出模糊幻影,混淆[target]的视线,令其难以辨别攻击方向。\"}\n{\"招式\":\"程序化拳法\",\"description\":\"[player]运用程序化拳法,以不断变化的攻击组合,让[target]难以预测招式,时而快时而慢,攻击变幻莫测。\",\"missing\":\"[player]运用程序化拳法,以不断变化的攻击组合,让[target]难以预测招式,攻击变幻莫测。\"}\n{\"招式\":\"预测之刃\",\"description\":\"[player]使出预测之刃,准确地预测[target]的下一步行动,犹如镜中水月,剑锋准确地击中[target]的要害。\",\"missing\":\"[player]使出预测之刃,准确地预测[target]的下一步行动,犹如镜中水月,剑锋迅速挥出。\"}\n{\"招式\":\"数据漩涡斩\",\"description\":\"[player]施展数据漩涡斩,利用[target]的动向,将其引导至剑刃之下,然后发动猛烈攻击,犹如漩涡将[target]吸入其中。\",\"missing\":\"[player]施展数据漩涡斩,利用[target]的动向,将其引导至剑刃之下,然后发动猛烈攻击,剑招异常犀利。\"}\n{\"招式\":\"算法刀舞\",\"description\":\"[player]挥舞着长剑,使出算法刀舞,刀法如算法一般精准,快速地切入[target]的防线,剑锋连续不断地斩向[target]。\",\"missing\":\"[player]挥舞着长剑,使出算法刀舞,刀法如算法一般精准,快速地切入[target]的防线,剑招变化多端。\"}\n{\"招式\":\"智能反击剑\",\"description\":\"[player]运用智能反击剑,反击[target]的招式,使其付出惨痛的代价,一瞬间的犹豫就足以让[target]受伤。\",\"missing\":\"[player]运用智能反击剑,反击[target]的招式,使其陷入困境,一瞬间的犹豫足以让[target]付出代价。\"}\n"}
2 | {"name": "冷子昂", "attr_str": "{\n \"name\": \"冷子昂\",\n \"description\": \"擅长冰系技能\",\n \"weapon\": \"冰刃\",\n \"major_martial_art\": \"冰霜寒刃功\",\n \"major_movements\": [\"冰刃斩破\", \"冰风流转\", \"冰龙穿云\", \"冰心彻骨\"],\n \"major_damage\": 80,\n \"secondary_martial_art\": \"冰封无影步\",\n \"secondary_movements\": [\"冰封幻影\", \"无影冻结\", \"冰刃闪耀\", \"冰封禅定\"],\n \"secondary_damage\": 70,\n \"footwork_and_body_method\": \"冰心护身法\",\n \"STR\": 8,\n \"VIT\": 6,\n \"SPD\": 15\n}\n", "skills": "\n{\"招式\":\"冰刃斩破\",\"description\":\"[player]聚集冰之力量于剑上,使出冰刃斩破,剑锋犹如寒冰之刃斩向[target]的要害部位,寒气逼人,剑光炽烈。\",\"missing\":\"[player]聚集冰之力量于剑上,使出冰刃斩破,剑锋犹如寒冰之刃,闪电般挥出。\"}\n{\"招式\":\"冰风流转\",\"description\":\"[player]身体如风一般旋转,同时释放出冰风刃,打击周围的敌人,冷飕飕的寒风环绕,[target]身不由己地被吹向一旁。\",\"missing\":\"[player]身体如风一般旋转,同时释放出冰风刃,冷飕飕的寒风环绕,风刃在[target]周围飞舞。\"}\n{\"招式\":\"冰龙穿云\",\"description\":\"[player]召唤出一条冰龙,冰龙穿越云层直扑[target],寒冰之力凝聚在龙爪之上,将[target]冻结一切,一切都难以抵挡。\",\"missing\":\"[player]召唤出一条冰龙,冰龙穿越云层,龙爪直扑[target],寒冰之力凝聚在龙爪之上,寒意森然。\"}\n{\"招式\":\"冰心彻骨\",\"description\":\"[player]凝聚冰之力于手,一触即可让[target]骨骼寒冷,动弹不得,彻底冰封,剑锋轻轻触及[target],寒意透骨。\",\"missing\":\"[player]凝聚冰之力于手,一触即可让[target]骨骼寒冷,动弹不得,寒气透骨,剑锋轻轻触及[target]。\"}\n{\"招式\":\"冰封幻影\",\"description\":\"[player]运用冰封无影步,快速移动,留下一道冰封的幻影,使[target]无法辨别真伪,幻影与实体交替出现,令[target]不知所措。\",\"missing\":\"[player]运用冰封无影步,快速移动,留下一道冰封的幻影,使[target]无法辨别真伪。\"}\n{\"招式\":\"无影冻结\",\"description\":\"[player]以极快的速度接近[target],然后冻结[target]的动作,使其陷入无法自拔的状态,如同身陷冰封之中,动弹不得。\",\"missing\":\"[player]以极快的速度接近[target],然后冻结[target]的动作,使其陷入无法自拔的状态。\"}\n{\"招式\":\"冰刃闪耀\",\"description\":\"[player]利用冰之能量,瞬间闪现至[target]身边,发动迅猛的攻击,剑锋如星光般闪烁,将[target]包围其中。\",\"missing\":\"[player]利用冰之能量,瞬间闪现至[target]身边,发动迅猛的攻击,剑锋如星光般闪烁。\"}\n{\"招式\":\"冰封禅定\",\"description\":\"[player]静心冥想,将身体冰封,使自己无法被[target]察觉,达到不可捉摸的状态,如同融入冰封禅定之中。\",\"missing\":\"[player]静心冥想,将身体冰封,使自己无法被[target]察觉,达到不可捉摸的状态。\"}\n"}
3 | {"name": "黄蓉", "attr_str": "{\n \"name\": \"黄蓉\",\n \"description\": \"丐帮帮主黄蓉,擅长打狗棒法和落英神剑掌,身法为逍遥游。\",\n \"weapon\": \"棒、剑\",\n \"major_martial_art\": \"打狗棒法\",\n \"major_movements\": [\"狗啸山林\", \"棒影重重\", \"狗尾续貂\", \"狗急跳墙\"],\n \"major_damage\": 90,\n \"secondary_martial_art\": \"落英神剑掌\",\n \"secondary_movements\": [\"落英如雨\", \"神剑破空\", \"飞花流水\", \"剑指苍穹\"],\n \"secondary_damage\": 80,\n \"footwork_and_body_method\": \"逍遥游\",\n \"STR\": 15,\n \"VIT\": 10,\n \"SPD\": 18\n}", "skills": "\n{\"招式\": \"狗啸山林\", \"description\": \"[player]手中长棒一挥,发出一声凄厉的狗啸,棒影如山林般扑向[target]\", \"missing\": \"[player]手中长棒一挥,发出一声凄厉的狗啸,棒影如山林般扑向[target]\"}\n{\"招式\": \"棒影重重\", \"description\": \"[player]身形连转,手中长棒化作无数道棒影,重重叠叠地向[target]砸去\", \"missing\": \"[player]身形连转,手中长棒化作无数道棒影,重重叠叠地向[target]砸去\"}\n{\"招式\": \"狗尾续貂\", \"description\": \"[player]手中长棒如狗尾续貂般灵动,连续变换方向,向[target]连续攻击\", \"missing\": \"[player]手中长棒如狗尾续貂般灵动,连续变换方向,向[target]连续攻击\"}\n{\"招式\": \"狗急跳墙\", \"description\": \"[player]猛地一跃,手中长棒带起狂风,如狗急跳墙般向[target]砸去\", \"missing\": \"[player]猛地一跃,手中长棒带起狂风,如狗急跳墙般向[target]砸去\"}\n{\"招式\": \"落英如雨\", \"description\": \"[player]身形一闪,双掌连续拍出,犹如漫天飘落的落英,掌风凌厉,瞬间覆盖[target]周身\", \"missing\": \"[player]身形一闪,双掌连续拍出,犹如漫天飘落的落英,掌风凌厉,向[target]周身袭去\"}\n{\"招式\": \"神剑破空\", \"description\": \"[player]手中剑光闪烁,一剑刺出,剑气凌厉无比,犹如神剑破开虚空,直指[target]要害\", \"missing\": \"[player]手中剑光闪烁,一剑刺出,剑气凌厉无比,直向[target]要害刺去\"}\n{\"招式\": \"飞花流水\", \"description\": \"[player]身形如飞,双掌连续拍击,掌风如流水般连绵不绝,将[target]团团围住\", \"missing\": \"[player]身形如飞,双掌连续拍击,掌风如流水般连绵不绝,向[target]团团包围\"}\n{\"招式\": \"剑指苍穹\", \"description\": \"[player]手中长剑一指,剑光直冲云霄,气势如虹,剑指直指苍穹,威力惊人\", \"missing\": \"[player]手中长剑一指,剑光直冲云霄,气势如虹,直指苍穹\"}\n"}
4 | {"name": "洪七公", "attr_str": "{\"name\": \"洪七公\", \"description\": \"丐帮掌门洪七公,精通降龙十八掌和打狗棒法\", \"weapon\": \"拳掌和棒\", \"major_martial_art\": \"降龙十八掌\", \"major_movements\": [\"龙腾九霄\", \"云龙翻江\", \"飞龙在天\", \"龙战于野\"], \"major_damage\": 120, \"secondary_martial_art\": \"打狗棒法\", \"secondary_movements\": [\"狗急跳墙\", \"棒打狗头\", \"狗尾续貂\", \"狗拿耗子\"], \"secondary_damage\": 100, \"footwork_and_body_method\": \"飞燕身法\", \"STR\": 15, \"VIT\": 10, \"SPD\": 18}", "skills": "{\"招式\": \"龙腾九霄\", \"description\": \"[player]双掌齐出,一招“龙腾九霄”,掌风凌厉,如千龙腾空般向[target]袭去\", \"missing\": \"[player]双掌齐出,一招“龙腾九霄”,掌风凌厉,如千龙腾空般向[target]袭去\"}\n{\"招式\": \"云龙翻江\", \"description\": \"[player]身形一转,双掌翻飞,一招“云龙翻江”,掌劲如滔滔江水,向[target]卷去\", \"missing\": \"[player]身形一转,双掌翻飞,一招“云龙翻江”,掌劲如滔滔江水,向[target]卷去\"}\n{\"招式\": \"飞龙在天\", \"description\": \"[player]身形一跃,双掌交错,一招“飞龙在天”,掌风呼啸,如飞龙般扑向[target]\", \"missing\": \"[player]身形一跃,双掌交错,一招“飞龙在天”,掌风呼啸,如飞龙般扑向[target]\"}\n{\"招式\": \"龙战于野\", \"description\": \"[player]双掌交错,一招“龙战于野”,掌劲纵横,如狂龙奔腾,向[target]猛攻而去\", \"missing\": \"[player]双掌交错,一招“龙战于野”,掌劲纵横,如狂龙奔腾,向[target]猛攻而去\"}\n{\"招式\": \"狗急跳墙\", \"description\": \"[player]手中棒法连绵不绝,一招“狗急跳墙”,棒影纵横,如狂风暴雨般压向[target]\", \"missing\": \"[player]手中棒法连绵不绝,一招“狗急跳墙”,棒影纵横,迅猛地向[target]压去\"}\n{\"招式\": \"棒打狗头\", \"description\": \"[player]手中棒法犹如闪电般迅猛,一招“棒打狗头”,棒影如电,准确地击中[target]的头部\", \"missing\": \"[player]手中棒法犹如闪电般迅猛,一招“棒打狗头”,棒影如电,向[target]的头部猛击\"}\n{\"招式\": \"狗尾续貂\", \"description\": \"[player]身形连绵不断,手中棒法灵动异常,一招“狗尾续貂”,棒影如狡黠的狐狸尾巴般迅速扫向[target]\", \"missing\": \"[player]身形连绵不断,手中棒法灵动异常,一招“狗尾续貂”,棒影迅速扫向[target],试图扰乱其防守\"}\n{\"招式\": \"狗拿耗子\", \"description\": \"[player]手中棒法灵巧异常,一招“狗拿耗子”,棒影如猎狗追捕耗子般迅速击中[target]\", \"missing\": \"[player]手中棒法灵巧异常,一招“狗拿耗子”,棒影迅速击向[target],试图捕捉住其身影\"}\n"}
5 | {"name": "马斯克", "attr_str": "{\"name\": \"马斯克\", \"description\": \"特斯拉的CEO,同时也是SpaceX的CEO\", \"weapon\": \"无\", \"major_martial_art\": \"电光雷动\", \"major_movements\": [\"磁引雷势\", \"电光狂风\", \"闪电瞬移\", \"雷霆突袭\"], \"major_damage\": 100, \"secondary_martial_art\": \"宇宙无敌\", \"secondary_movements\": [\"宇宙爆破\", \"星光炸裂\", \"虚空吞噬\", \"星际陷阱\"], \"secondary_damage\": 120, \"footwork_and_body_method\": \"电光护体\", \"STR\": 15, \"VIT\": 10, \"SPD\": 18}", "skills": "{\"招式\": \"磁引雷势\", \"description\": \"[player]双手结印,内力运转,犹如磁铁般吸引周围的雷电能量,聚集于体内,随后一声怒喝,释放出一道磁引雷势,雷电纵横交错,威力惊人。\", \"missing\": \"[player]双手结印,内力运转,犹如磁铁般吸引周围的雷电能量,聚集于体内,随后一声怒喝,释放出一道磁引雷势,雷电纵横交错。\"}\n{\"招式\": \"电光狂风\", \"description\": \"[player]身形如电,迅猛无比,双手化作电光,犹如狂风般扑向[target],速度之快令人难以捉摸。\", \"missing\": \"[player]身形如电,迅猛无比,双手化作电光,犹如狂风般扑向[target],速度之快令人难以捉摸。\"}\n{\"招式\": \"闪电瞬移\", \"description\": \"[player]身形一晃,如同闪电般瞬间消失在原地,下一刻已经出现在[target]身旁,犹如闪电般的瞬移之术。\", \"missing\": \"[player]身形一晃,如同闪电般瞬间消失在原地,下一刻已经出现在[target]身旁,犹如闪电般的瞬移之术。\"}\n{\"招式\": \"雷霆突袭\", \"description\": \"[player]全身散发出雷霆般的气势,如疾风般冲向[target],拳脚交替,每一招都带着雷霆之力,威力惊人。\", \"missing\": \"[player]全身散发出雷霆般的气势,如疾风般冲向[target],拳脚交替,每一招都带着雷霆之力。\"}\n{\"招式\": \"宇宙爆破\", \"description\": \"[player]聚集宇宙能量,猛然爆发,一道炽热的能量冲击波向[target]迸发,瞬间将周围的一切炸成碎片\", \"missing\": \"[player]聚集宇宙能量,猛然爆发,一道炽热的能量冲击波向[target]迸发,将周围的一切震荡不已\"}\n{\"招式\": \"星光炸裂\", \"description\": \"[player]手指轻弹,星光四溅,无数颗明亮的星辰爆炸开来,形成一片炫目的光芒,将[target]笼罩其中\", \"missing\": \"[player]手指轻弹,星光四溅,无数颗明亮的星辰爆炸开来,形成一片炫目的光芒,照亮了整个战场\"}\n{\"招式\": \"虚空吞噬\", \"description\": \"[player]张开双臂,周围的虚空开始扭曲,一股强大的吸力将[target]紧紧吸附过来,仿佛要将其吞噬殆尽\", \"missing\": \"[player]张开双臂,周围的虚空开始扭曲,一股强大的吸力将[target]紧紧吸附过来,使其无法逃脱\"}\n{\"招式\": \"星际陷阱\", \"description\": \"[player]手指一点,星光凝聚成一道巨大的星际陷阱,将[target]困在其中,无法逃脱\", \"missing\": \"[player]手指一点,星光凝聚成一道巨大的星际陷阱,将[target]困在其中,试图逃脱却无法成功\"}\n"}
6 | {"name": "马斯克", "attr_str": "{\"name\": \"马斯克\", \"description\": \"特斯拉的CEO,同时也是SpaceX的CEO\", \"weapon\": \"无\", \"major_martial_art\": \"电光雷动\", \"major_movements\": [\"磁引雷势\", \"电光狂风\", \"闪电瞬移\", \"雷霆突袭\"], \"major_damage\": 100, \"secondary_martial_art\": \"宇宙无敌\", \"secondary_movements\": [\"宇宙爆破\", \"星光炸裂\", \"虚空吞噬\", \"星际陷阱\"], \"secondary_damage\": 120, \"footwork_and_body_method\": \"电光护体\", \"STR\": 15, \"VIT\": 10, \"SPD\": 18}", "skills": "{\"招式\": \"磁引雷势\", \"description\": \"[player]双手结印,内力运转,犹如磁铁般吸引周围的雷电元素,形成一股强大的雷势,向[target]猛烈冲击而去\", \"missing\": \"[player]双手结印,内力运转,吸引周围的雷电元素,形成一股雷势,向[target]冲击而去\"}\n{\"招式\": \"电光狂风\", \"description\": \"[player]身形如电,手中电光闪烁的兵器犹如狂风般挥舞,迅猛无比,将[target]困在电光之中\", \"missing\": \"[player]身形如电,手中电光闪烁的兵器犹如狂风般挥舞,迅猛无比,将[target]困在电光之中\"}\n{\"招式\": \"闪电瞬移\", \"description\": \"[player]身形瞬间消失在一道闪电之中,下一刻已经出现在[target]身旁,发动突袭攻击\", \"missing\": \"[player]身形瞬间消失在一道闪电之中,下一刻已经出现在[target]身旁,试图发动突袭攻击\"}\n{\"招式\": \"雷霆突袭\", \"description\": \"[player]如雷霆般迅猛冲击,身法灵动异常,犹如闪电一般突袭[target],使出连绵不绝的攻击\", \"missing\": \"[player]如雷霆般迅猛冲击,身法灵动异常,犹如闪电一般突袭[target],试图使出连绵不绝的攻击\"}\n{\"招式\": \"宇宙爆破\", \"description\": \"[player]聚集宇宙能量,猛然爆发,一道炽热的能量冲击波向[target]迸发,瞬间将周围的一切化为灰烬\", \"missing\": \"[player]聚集宇宙能量,猛然爆发,一道炽热的能量冲击波向[target]迸发,将周围的一切烧得焦黑\"}\n{\"招式\": \"星光炸裂\", \"description\": \"[player]手指轻弹,星光四溅,无数颗明亮的星辰化作炽热的碎片,向[target]迅速飞射而去\", \"missing\": \"[player]手指轻弹,星光四溅,无数颗明亮的星辰化作碎片,向[target]飞射而去\"}\n{\"招式\": \"虚空吞噬\", \"description\": \"[player]张口一吸,周围的空气瞬间被虚空吞噬,形成一股强大的吸力,将[target]紧紧吸附在一起\", \"missing\": \"[player]张口一吸,周围的空气被虚空吞噬,形成一股强大的吸力,试图将[target]吸附在一起\"}\n{\"招式\": \"星际陷阱\", \"description\": \"[player]手指连连点动,星光闪烁,一道巨大的星际陷阱形成,将[target]困在其中,无法逃脱\", \"missing\": \"[player]手指点动,星光闪烁,一道星际陷阱形成,试图将[target]困在其中,但[target]灵巧地躲过了陷阱\"}\n"}
7 | {"name": "阿泰斯特", "attr_str": "{\"name\": \"阿泰斯特\", \"description\": \"阿泰斯特是一位师从的剑法高手,擅长使用剑进行战斗。\", \"weapon\": \"剑\", \"major_martial_art\": \"剑心诀\", \"major_movements\": [\"飞龙剑法\", \"无影剑术\"], \"major_damage\": 80, \"secondary_martial_art\": \"无影步\", \"secondary_movements\": [\"影隐身法\", \"影遁幻影\", \"影舞风行\", \"影敛身法\"], \"secondary_damage\": 60, \"footwork_and_body_method\": \"无影步\", \"STR\": 15, \"VIT\": 10, \"SPD\": 18}", "skills": "{\"招式\": \"飞龙剑法\", \"description\": \"[player]身形如飞龙般纵跃而起,手中长剑化作一道银色闪电,迅猛无比地刺向[target]\", \"missing\": \"[player]身形如飞龙般纵跃而起,手中长剑化作一道银色闪电,迅猛地刺向[target],但被[target]巧妙地躲开了\"}\n{\"招式\": \"无影剑术\", \"description\": \"[player]身形如鬼魅般闪动,手中长剑化作无数剑影,犹如无影之剑一般,迅速刺向[target]\", \"missing\": \"[player]身形如鬼魅般闪动,手中长剑化作无数剑影,犹如无影之剑一般,迅速刺向[target],但被[target]灵巧地躲开了\"}\n{\"招式\": \"影隐身法\", \"description\": \"[player]身形如影,忽隐忽现,犹如一缕轻烟般飘忽不定,使出了一招“影隐身法”。\", \"missing\": \"[player]身形如影,忽隐忽现,犹如一缕轻烟般飘忽不定,施展出了一招“影隐身法”。\"}\n{\"招式\": \"影遁幻影\", \"description\": \"[player]身形如鬼魅般闪烁,幻影重重,使出了一招“影遁幻影”,让人难以分辨真假。\", \"missing\": \"[player]身形如鬼魅般闪烁,幻影重重,施展出了一招“影遁幻影”,让人难以分辨真假。\"}\n{\"招式\": \"影舞风行\", \"description\": \"[player]身形如风,瞬间穿梭于敌人之间,宛如一阵狂风般迅捷无比,使出了一招“影舞风行”。\", \"missing\": \"[player]身形如风,瞬间穿梭于敌人之间,宛如一阵狂风般迅捷无比,施展出了一招“影舞风行”。\"}\n{\"招式\": \"影敛身法\", \"description\": \"[player]身形一闪,瞬间消失在原地,仿佛融入了周围的黑暗中,使出了一招“影敛身法”。\", \"missing\": \"[player]身形一闪,瞬间消失在原地,仿佛融入了周围的黑暗中,施展出了一招“影敛身法”。\"}\n"}
8 | {"name": "尤尼控", "attr_str": "{\"name\": \"尤尼控\", \"description\": \"师从,主修剑法\", \"weapon\": \"剑\", \"major_martial_art\": \"剑法\", \"major_movements\": [\"乱影斩\", \"飞花落\", \"星光破\", \"归心剑\"], \"major_damage\": 90, \"secondary_martial_art\": \"无影剑法\", \"secondary_movements\": [\"影随身动\", \"无形斩\", \"幻影步\", \"风雷剑\"], \"secondary_damage\": 80, \"footwork_and_body_method\": \"流云身法\", \"STR\": 15, \"VIT\": 10, \"SPD\": 18}", "skills": "{\"招式\": \"乱影斩\", \"description\": \"[player]手中剑舞动如风,剑影纷飞,一招“乱影斩”,剑光如雨,向[target]砍去\", \"missing\": \"[player]手中剑舞动如风,剑影纷飞,一招“乱影斩”,剑光如雨,划向[target]\"}\n{\"招式\": \"飞花落\", \"description\": \"[player]身形飘忽,手中剑化作一片花瓣飞舞,一招“飞花落”,剑花纷纷落下,覆盖了[target]周围的区域\", \"missing\": \"[player]身形飘忽,手中剑化作一片花瓣飞舞,一招“飞花落”,剑花纷纷落下,覆盖了周围的区域\"}\n{\"招式\": \"星光破\", \"description\": \"[player]剑势如星光闪烁,一招“星光破”,剑光瞬间爆发,直刺[target]的要害之处\", \"missing\": \"[player]剑势如星光闪烁,一招“星光破”,剑光瞬间爆发,刺向[target]的要害之处\"}\n{\"招式\": \"归心剑\", \"description\": \"[player]心神专注,手中剑迅速刺出,一招“归心剑”,剑气凌厉,直取[target]的心脏\", \"missing\": \"[player]心神专注,手中剑迅速刺出,一招“归心剑”,剑气凌厉,刺向[target]的心脏\"}\n{\"招式\": \"影随身动\", \"description\": \"[player]身形如鬼魅般闪动,剑光如影随形,一招“影随身动”,剑影纷飞,迅速刺向[target]\", \"missing\": \"[player]身形如鬼魅般闪动,剑光如影随形,一招“影随身动”,剑影纷飞,迅速刺向[target]\"}\n{\"招式\": \"无形斩\", \"description\": \"[player]手中剑化作一道无形之光,瞬间划过,一招“无形斩”,剑气悄然无声地斩向[target]\", \"missing\": \"[player]手中剑化作一道无形之光,瞬间划过,一招“无形斩”,剑气悄然无声地斩向[target]\"}\n{\"招式\": \"幻影步\", \"description\": \"[player]身形如幻,步伐飘忽不定,一招“幻影步”,如鬼魅般接近[target],剑光闪烁间刺向[target]\", \"missing\": \"[player]身形如幻,步伐飘忽不定,一招“幻影步”,如鬼魅般接近[target],剑光闪烁间刺向[target]\"}\n{\"招式\": \"风雷剑\", \"description\": \"[player]手中剑舞动如风,剑光如雷,一招“风雷剑”,剑气凌厉地劈向[target]\", \"missing\": \"[player]手中剑舞动如风,剑光如雷,一招“风雷剑”,剑气凌厉地劈向[target]\"}\n"}
9 | {"name": "马斯克", "attr_str": "{\"name\": \"马斯克\", \"description\": \"师从,主修贱法\", \"weapon\": \"无\", \"major_martial_art\": \"贱影剑法\", \"major_movements\": [\"贱魂剑\", \"飞贱剑\", \"贱影斩\", \"贱魄刺\"], \"major_damage\": 80, \"secondary_martial_art\": \"贱魔掌法\", \"secondary_movements\": [\"贱魔掌\", \"贱魔爆\", \"贱魔崩\", \"贱魔震\"], \"secondary_damage\": 90, \"footwork_and_body_method\": \"贱魂身法\", \"STR\": 10, \"VIT\": 7, \"SPD\": 13}", "skills": "{\"招式\": \"贱魂剑\", \"description\": \"[player]手中剑舞动如鬼魅,一招“贱魂剑”,剑光幻化成无数剑影,迅猛无比地向[target]刺去\", \"missing\": \"[player]手中剑舞动如鬼魅,一招“贱魂剑”,剑光幻化成无数剑影,迅猛地刺向[target],但被[target]巧妙地躲开\"}\n{\"招式\": \"飞贱剑\", \"description\": \"[player]身形如飞,手中剑化作一道剑光,一招“飞贱剑”,剑光疾射而出,直奔[target]而去\", \"missing\": \"[player]身形如飞,手中剑化作一道剑光,一招“飞贱剑”,剑光疾射而出,但被[target]灵巧地闪避开\"}\n{\"招式\": \"贱影斩\", \"description\": \"[player]剑势如影,一招“贱影斩”,剑光如幻,迅猛地斩向[target]\", \"missing\": \"[player]剑势如影,一招“贱影斩”,剑光如幻,迅猛地斩向[target],但被[target]巧妙地躲开\"}\n{\"招式\": \"贱魄刺\", \"description\": \"[player]剑尖微微颤动,一招“贱魄刺”,剑光闪烁,直刺[target]要害\", \"missing\": \"[player]剑尖微微颤动,一招“贱魄刺”,剑光闪烁,直刺[target]要害,但被[target]巧妙地避开\"}\n{\"招式\": \"贱魔掌\", \"description\": \"[player]双掌连环拍击,招式狠辣凌厉,掌风呼啸,犹如恶魔之爪一般\", \"missing\": \"[player]双掌连环拍击,招式凌厉异常,掌风呼啸,犹如恶魔之爪一般\"}\n{\"招式\": \"贱魔爆\", \"description\": \"[player]双掌骤然爆发,内力迸发,一股炽热的能量从掌心迸发而出,如同恶魔之力一般\", \"missing\": \"[player]双掌骤然爆发,内力迸发,一股能量从掌心迸发而出,如同恶魔之力一般\"}\n{\"招式\": \"贱魔崩\", \"description\": \"[player]双掌猛地向下击落,劲力犹如山崩地裂,威势惊人,恶魔之力凝聚于掌心\", \"missing\": \"[player]双掌猛地向下击落,劲力犹如山崩地裂,威势惊人,恶魔之力凝聚于掌心\"}\n{\"招式\": \"贱魔震\", \"description\": \"[player]双掌猛地一震,内力迸发,掌风如雷霆般炸响,恶魔之力肆虐于空气中\", \"missing\": \"[player]双掌猛地一震,内力迸发,掌风炸响,恶魔之力肆虐于空气中\"}\n"}
10 | {"name": "马斯克", "attr_str": "{\"name\": \"马斯克\", \"description\": \"特斯拉的CEO,同时也是SpaceX的CEO\", \"weapon\": \"无\", \"major_martial_art\": \"电光雷动\", \"major_movements\": [\"磁引雷势\", \"电光狂风\", \"闪电瞬移\", \"雷霆突袭\"], \"major_damage\": 100, \"secondary_martial_art\": \"宇宙无敌\", \"secondary_movements\": [\"宇宙爆破\", \"星光炸裂\", \"虚空吞噬\", \"星际陷阱\"], \"secondary_damage\": 120, \"footwork_and_body_method\": \"电光护体\", \"STR\": 15, \"VIT\": 10, \"SPD\": 18}", "skills": "{\"招式\": \"磁引雷势\", \"description\": \"[player]双手结印,内力运转,周身电光闪烁,一股强大的磁场形成,吸引雷电之力,聚集于[player]身周\", \"missing\": \"[player]双手结印,内力运转,周身电光闪烁,一股强大的磁场形成,吸引雷电之力,聚集于[player]身周\"}\n{\"招式\": \"电光狂风\", \"description\": \"[player]身形如电,迅猛无比地挥动双臂,激起一阵狂风,电光四溅,将[target]笼罩其中\", \"missing\": \"[player]身形如电,迅猛无比地挥动双臂,激起一阵狂风,电光四溅,向[target]袭来\"}\n{\"招式\": \"闪电瞬移\", \"description\": \"[player]身形一晃,如闪电般瞬间移动到[target]身旁,手中电光闪烁的兵器刺向[target]\", \"missing\": \"[player]身形一晃,如闪电般瞬间移动到[target]身旁,手中电光闪烁的兵器刺向[target]\"}\n{\"招式\": \"雷霆突袭\", \"description\": \"[player]迅雷不及掩耳之势,如雷霆般突然袭向[target],手中兵器带着雷电之力猛然刺出\", \"missing\": \"[player]迅雷不及掩耳之势,如雷霆般突然袭向[target],手中兵器带着雷电之力刺向[target]\"}\n{\"招式\": \"宇宙爆破\", \"description\": \"[player]聚集宇宙能量,猛然爆发,一道炽热的能量波向[target]迸发,瞬间将周围的一切都化为灰烬\", \"missing\": \"[player]聚集宇宙能量,猛然爆发,一道炽热的能量波向[target]迸发,周围的一切都被炽热的能量包围\"}\n{\"招式\": \"星光炸裂\", \"description\": \"[player]手指轻弹,星光四溅,无数颗明亮的星辰化为碎片,向[target]飞溅而去\", \"missing\": \"[player]手指轻弹,星光四溅,无数颗明亮的星辰化为碎片,闪烁着美丽的光芒\"}\n{\"招式\": \"虚空吞噬\", \"description\": \"[player]张开双臂,虚空开始扭曲,一道黑洞形成,将[target]周围的一切都吞噬进去\", \"missing\": \"[player]张开双臂,虚空开始扭曲,一道黑洞形成,周围的一切都被黑暗笼罩\"}\n{\"招式\": \"星际陷阱\", \"description\": \"[player]施展出星际之力,星光凝聚形成一道无形的陷阱,将[target]困于其中\", \"missing\": \"[player]施展出星际之力,星光凝聚形成一道无形的陷阱,将[target]包围\"}\n"}
11 | {"name": "杨振宁", "attr_str": "{\"name\": \"杨振宁\", \"description\": \"高能物理大师\", \"weapon\": \"剑\", \"major_martial_art\": \"量子风暴剑法\", \"major_movements\": [\"乾坤剑气\", \"虚空瞬移\", \"粒子爆发\", \"时空禁锢\"], \"major_damage\": 120, \"secondary_martial_art\": \"黑洞掌法\", \"secondary_movements\": [\"虚空吸引\", \"旋转黑洞\", \"引力压制\", \"空间崩溃\"], \"secondary_damage\": 100, \"footwork_and_body_method\": \"时空幻影步\", \"STR\": 15, \"VIT\": 10, \"SPD\": 18}", "skills": "{\"招式\": \"乾坤剑气\", \"description\": \"[player]手中剑舞动不停,剑气纵横交错,一股强大的气势凝聚而成,形成一道犹如乾坤之力的剑气,直奔[target]而去\", \"missing\": \"[player]手中剑舞动不停,剑气纵横交错,形成一道犹如乾坤之力的剑气,迅速向[target]飞去\"}\n{\"招式\": \"虚空瞬移\", \"description\": \"[player]身形忽然消失在原地,下一刻却已出现在[target]身后,手中剑光闪烁,一招“虚空瞬移”刺向[target]\", \"missing\": \"[player]身形忽然消失在原地,下一刻却已出现在[target]身后,手中剑光闪烁,试图一招“虚空瞬移”刺向[target]\"}\n{\"招式\": \"粒子爆发\", \"description\": \"[player]全身内力迸发,剑法变得迅猛无比,剑光如粒子般闪烁,一招“粒子爆发”瞬间击中[target],爆发出强大的力量\", \"missing\": \"[player]全身内力迸发,剑法变得迅猛无比,剑光如粒子般闪烁,试图一招“粒子爆发”击中[target],释放出强大的力量\"}\n{\"招式\": \"时空禁锢\", \"description\": \"[player]剑势凌厉,剑光闪烁,一招“时空禁锢”使得时间和空间仿佛被禁锢,将[target]困在其中无法动弹\", \"missing\": \"[player]剑势凌厉,剑光闪烁,试图一招“时空禁锢”使得时间和空间仿佛被禁锢,试图将[target]困在其中\"}\n{\"招式\": \"虚空吸引\", \"description\": \"[player]双掌一推,内力涌动,形成一股强大的吸引力,如同虚空中有无形之手将[target]牢牢吸引过来\", \"missing\": \"[player]双掌一推,内力涌动,形成一股强大的吸引力,试图将[target]吸引过来\"}\n{\"招式\": \"旋转黑洞\", \"description\": \"[player]身形急转,双掌迅速旋转,形成一股旋转的黑洞之力,向[target]猛然压去\", \"missing\": \"[player]身形急转,双掌迅速旋转,形成一股旋转的黑洞之力,试图向[target]压去\"}\n{\"招式\": \"引力压制\", \"description\": \"[player]双掌猛地向下一压,内力凝聚成强大的引力,将[target]牢牢压制在地面上,动弹不得\", \"missing\": \"[player]双掌猛地向下一压,内力凝聚成强大的引力,试图将[target]压制在地面上\"}\n{\"招式\": \"空间崩溃\", \"description\": \"[player]双掌猛然合拢,内力爆发,周围空间发生剧烈扭曲,形成一片空间崩溃,将[target]困于其中\", \"missing\": \"[player]双掌猛然合拢,内力爆发,周围空间发生剧烈扭曲,试图将[target]困于其中\"}\n"}
12 |
--------------------------------------------------------------------------------
/demo_code/edge_data_2.txt:
--------------------------------------------------------------------------------
1 | Source|Target|Events|Transition
2 | -|-|-|-
3 | 1|2|英灵殿->北方之路|选择北方之路,与北方怪兽作战
4 | 1|3|英灵殿->黑暗森林之路|(挑战)选择黑暗森林之路,面对隐匿的黑暗生物
5 | 2|4|北方之路->冰原巨人|通过北方之路,遇到冰原巨人
6 | 3|4|黑暗森林之路->冰原巨人|通过黑暗森林,也来到了冰原巨人面前
7 | 4|5|冰原巨人->黑暗精灵|打败冰原巨人,遇到速度极快的黑暗精灵
8 | 4|6|冰原巨人->恶龙法夫纳|(挑战)打败冰原巨人,有资格挑战恶龙法夫纳
9 | 5|7|黑暗精灵->山地巨人|通过黑暗精灵的挑战,迎来山地巨人
10 | 6|7|恶龙法夫纳->山地巨人|通过恶龙的挑战,遇上山地巨人
11 | 7|8|山地巨人->北地冰原巨熊|打败山地巨人,遭遇北地冰原巨熊
12 | 7|9|山地巨人->海姆冥界使者|(挑战)打败山地巨人,有资格挑战海姆冥界使者
13 | 8|10|北地冰原巨熊->最后试炼|通过北地冰原巨熊,来到最后试炼
14 | 9|10|海姆冥界使者->最后试炼|通过海姆冥界使者,来到最后试炼
--------------------------------------------------------------------------------
/demo_code/gradio_baichuan.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "provenance": []
7 | },
8 | "kernelspec": {
9 | "name": "python3",
10 | "display_name": "Python 3"
11 | },
12 | "language_info": {
13 | "name": "python"
14 | }
15 | },
16 | "cells": [
17 | {
18 | "cell_type": "code",
19 | "source": [
20 | "import requests\n",
21 | "import json\n",
22 | "import time\n",
23 | "import hashlib\n",
24 | "\n",
25 | "\n",
26 | "def calculate_md5(input_string):\n",
27 | " md5 = hashlib.md5()\n",
28 | " md5.update(input_string.encode('utf-8'))\n",
29 | " encrypted = md5.hexdigest()\n",
30 | " return encrypted\n",
31 | "\n",
32 | "def chat_baichuan(message):\n",
33 | " url = \"https://api.baichuan-ai.com/v1/chat\"\n",
34 | " api_key = \"ffee2327cce6\"\n",
35 | " secret_key = \"QK3yI9oTY=\"\n",
36 | "\n",
37 | " data = {\n",
38 | " \"model\": \"Baichuan2-53B\",\n",
39 | " \"messages\": [\n",
40 | " {\n",
41 | " \"role\": \"user\",\n",
42 | " \"content\": message\n",
43 | " }\n",
44 | " ]\n",
45 | " }\n",
46 | "\n",
47 | " json_data = json.dumps(data)\n",
48 | " time_stamp = int(time.time())\n",
49 | " signature = calculate_md5(secret_key + json_data + str(time_stamp))\n",
50 | "\n",
51 | " headers = {\n",
52 | " \"Content-Type\": \"application/json\",\n",
53 | " \"Authorization\": \"Bearer \" + api_key,\n",
54 | " \"X-BC-Request-Id\": \"your requestId\",\n",
55 | " \"X-BC-Timestamp\": str(time_stamp),\n",
56 | " \"X-BC-Signature\": signature,\n",
57 | " \"X-BC-Sign-Algo\": \"MD5\",\n",
58 | " }\n",
59 | "\n",
60 | " response = requests.post(url, data=json_data, headers=headers)\n",
61 | "\n",
62 | " if response.status_code != 200:\n",
63 | " print(\"请求失败,状态码:\", response.status_code)\n",
64 | " return None\n",
65 | " # print(\"请求成功!\")\n",
66 | " # print(\"响应header:\", response.headers)\n",
67 | " # print(\"响应body:\", response.text)\n",
68 | " data = json.loads(response.text)\n",
69 | " return data[\"data\"][\"messages\"][0][\"content\"]\n",
70 | "\n",
71 | "\n",
72 | "if __name__ == \"__main__\":\n",
73 | " ans = chat_baichuan(\"你是谁\")\n",
74 | " print(ans)\n"
75 | ],
76 | "metadata": {
77 | "colab": {
78 | "base_uri": "https://localhost:8080/"
79 | },
80 | "id": "XQjZnrRuKNt5",
81 | "outputId": "8f4bce88-cb4b-486d-912f-ed0acb67e781"
82 | },
83 | "execution_count": null,
84 | "outputs": [
85 | {
86 | "output_type": "stream",
87 | "name": "stdout",
88 | "text": [
89 | "我叫百川大模型,是由百川智能的工程师们创造的大语言模型,我可以和人类进行自然交流、解答问题、协助创作,帮助大众轻松、普惠的获得世界知识和专业服务。如果你有任何问题,可以随时向我提问\n"
90 | ]
91 | }
92 | ]
93 | },
94 | {
95 | "cell_type": "code",
96 | "source": [
97 | "!pip -q install gradio langchain tiktoken openai"
98 | ],
99 | "metadata": {
100 | "colab": {
101 | "base_uri": "https://localhost:8080/"
102 | },
103 | "id": "NMQakT--RGF4",
104 | "outputId": "52e42689-6aac-4b35-ebc0-6a6514f9e4ef"
105 | },
106 | "execution_count": null,
107 | "outputs": [
108 | {
109 | "output_type": "stream",
110 | "name": "stdout",
111 | "text": [
112 | "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m20.3/20.3 MB\u001b[0m \u001b[31m66.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
113 | "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.9/1.9 MB\u001b[0m \u001b[31m78.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
114 | "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.0/2.0 MB\u001b[0m \u001b[31m84.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
115 | "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m77.0/77.0 kB\u001b[0m \u001b[31m7.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
116 | "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m66.3/66.3 kB\u001b[0m \u001b[31m6.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
117 | "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
118 | "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m298.8/298.8 kB\u001b[0m \u001b[31m32.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
119 | "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m75.7/75.7 kB\u001b[0m \u001b[31m8.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
120 | "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m302.0/302.0 kB\u001b[0m \u001b[31m28.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
121 | "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m138.7/138.7 kB\u001b[0m \u001b[31m16.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
122 | "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m45.7/45.7 kB\u001b[0m \u001b[31m5.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
123 | "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m59.5/59.5 kB\u001b[0m \u001b[31m5.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
124 | "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m129.9/129.9 kB\u001b[0m \u001b[31m16.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
125 | "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m40.0/40.0 kB\u001b[0m \u001b[31m4.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
126 | "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m49.4/49.4 kB\u001b[0m \u001b[31m5.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
127 | "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m58.3/58.3 kB\u001b[0m \u001b[31m5.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
128 | "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m67.0/67.0 kB\u001b[0m \u001b[31m6.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
129 | "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m76.0/76.0 kB\u001b[0m \u001b[31m7.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
130 | "\u001b[?25h Building wheel for ffmpy (setup.py) ... \u001b[?25l\u001b[?25hdone\n"
131 | ]
132 | }
133 | ]
134 | },
135 | {
136 | "cell_type": "code",
137 | "execution_count": null,
138 | "metadata": {
139 | "colab": {
140 | "base_uri": "https://localhost:8080/",
141 | "height": 704
142 | },
143 | "id": "tTxSyejrQ8HS",
144 | "outputId": "a698eb99-3906-420b-b328-58677dc75fd6"
145 | },
146 | "outputs": [
147 | {
148 | "metadata": {
149 | "tags": null
150 | },
151 | "name": "stdout",
152 | "output_type": "stream",
153 | "text": [
154 | "Colab notebook detected. This cell will run indefinitely so that you can see errors and logs. To turn off, set debug=False in launch().\n",
155 | "Running on public URL: https://82acbd8c5d771378a4.gradio.live\n",
156 | "\n",
157 | "This share link expires in 72 hours. For free permanent hosting and GPU upgrades, run `gradio deploy` from Terminal to deploy to Spaces (https://huggingface.co/spaces)\n"
158 | ]
159 | },
160 | {
161 | "data": {
162 | "text/html": [
163 | ""
164 | ],
165 | "text/plain": [
166 | ""
167 | ]
168 | },
169 | "metadata": {},
170 | "output_type": "display_data"
171 | },
172 | {
173 | "output_type": "stream",
174 | "name": "stdout",
175 | "text": [
176 | "{\"name\": \"乔峰\", \"attr_str\": \"{\\\"name\\\": \\\"乔峰\\\", \\\"description\\\": \\\"一位少林派的武林高手,擅长降龙十八掌和打狗棒法\\\", \\\"weapon\\\": \\\"拳\\\", \\\"major_martial_art\\\": \\\"少林派内功\\\", \\\"major_movements\\\": [\\\"禅定\\\", \\\"强身\\\"], \\\"major_damage\\\": 60, \\\"secondary_martial_art\\\": \\\"打狗棒法\\\", \\\"secondary_movements\\\": [\\\"恶狗拦路\\\", \\\"拨狗朝天\\\", \\\"狗急跳墙\\\", \\\"狗尾续貂\\\"], \\\"secondary_damage\\\": 80, \\\"footwork_and_body_method\\\": \\\"金钟罩\\\", \\\"STR\\\": 15, \\\"VIT\\\": 10, \\\"SPD\\\": 10}\", \"skills\": \"{\\\"招式\\\": \\\"禅定\\\", \\\"description\\\": \\\"[player]运起少林派内功心法,进入禅定状态,心境空明,内外如一,气息悠长,精神焕发。\\\", \\\"missing\\\": \\\"[player]运起少林派内功心法,进入禅定状态,心境空明,内外如一,气息悠长,精神焕发。\\\"}\\n{\\\"招式\\\": \\\"强身\\\", \\\"description\\\": \\\"[player]运用少林派内功心法,以气催力,强化自身筋骨,提高抗击打能力。\\\", \\\"missing\\\": \\\"[player]运用少林派内功心法,以气催力,强化自身筋骨,提高抗击打能力。\\\"}\\n{\\\"招式\\\": \\\"恶狗拦路\\\", \\\"description\\\": \\\"[player]手中竹棒挥出,一招“恶狗拦路”,横打过去,将[target]逼退数步\\\", \\\"missing\\\": \\\"[player]手中竹棒挥出,一招“恶狗拦路”,横打过去,将[target]逼退数步\\\"}\\n{\\\"招式\\\": \\\"拨狗朝天\\\", \\\"description\\\": \\\"[player]手中竹棒突然翻过,使一招“拨狗朝天”,将[target]手中的兵刃拨开\\\", \\\"missing\\\": \\\"[player]手中竹棒突然翻过,使一招“拨狗朝天”,将[target]手中的兵刃拨开\\\"}\\n{\\\"招式\\\": \\\"狗急跳墙\\\", \\\"description\\\": \\\"[player]身形一晃,使一招“狗急跳墙”,避开了[target]的攻击\\\", \\\"missing\\\": \\\"[player]身形一晃,使一招“狗急跳墙”,避开了[target]的攻击\\\"}\\n{\\\"招式\\\": \\\"狗尾续貂\\\", \\\"description\\\": \\\"[player]手中竹棒疾挥,使一招“狗尾续貂”,将[target]逼得节节后退\\\", \\\"missing\\\": \\\"[player]手中竹棒疾挥,使一招“狗尾续貂”,将[target]逼得节节后退\\\"}\\n\"}\n",
177 | "{\"name\": \"乔峰\", \"attr_str\": \"{\\\"name\\\": \\\"乔峰\\\", \\\"description\\\": \\\"大宋丐帮帮主,绝技有降龙十八掌和打狗棒法\\\", \\\"weapon\\\": \\\"棍\\\", \\\"major_martial_art\\\": \\\"降龙十八掌\\\", \\\"major_movements\\\": [\\\"亢龙有悔\\\", \\\"飞龙在天\\\", \\\"见龙在田\\\", \\\"潜龙勿用\\\"], \\\"major_damage\\\": 100, \\\"secondary_martial_art\\\": \\\"打狗棒法\\\", \\\"secondary_movements\\\": [\\\"挑字诀\\\", \\\"戳字诀\\\", \\\"劈字诀\\\", \\\"扫字诀\\\"], \\\"secondary_damage\\\": 90, \\\"footwork_and_body_method\\\": \\\"游龙步\\\", \\\"STR\\\": 15, \\\"VIT\\\": 10, \\\"SPD\\\": 12}\", \"skills\": \"{\\\"招式\\\": \\\"亢龙有悔\\\", \\\"description\\\": \\\"[player]运起降龙十八掌中的“亢龙有悔”,一股浑厚的掌力瞬间涌出,直击[target]胸口\\\", \\\"missing\\\": \\\"[player]运起降龙十八掌中的“亢龙有悔”,一股浑厚的掌力瞬间涌出,直奔[target]而去\\\"}\\n{\\\"招式\\\": \\\"飞龙在天\\\", \\\"description\\\": \\\"[player]身形一晃,使出“飞龙在天”,双掌齐推,犹如双龙出海,气势磅礴,直逼[target]\\\", \\\"missing\\\": \\\"[player]身形一晃,使出“飞龙在天”,双掌齐推,犹如双龙出海,气势磅礴,向[target]压去\\\"}\\n{\\\"招式\\\": \\\"见龙在田\\\", \\\"description\\\": \\\"[player]运起内力,使出“见龙在田”,双掌推出,犹如巨浪拍岸,势不可挡,击中[target]的胸膛\\\", \\\"missing\\\": \\\"[player]运起内力,使出“见龙在田”,双掌推出,犹如巨浪拍岸,势不可挡,击向[target]的胸膛\\\"}\\n{\\\"招式\\\": \\\"潜龙勿用\\\", \\\"description\\\": \\\"[player]深吸一口气,使出“潜龙勿用”,双掌缓缓推出,看似平淡无奇,实则暗藏汹涌,击中[target]的腹部\\\", \\\"missing\\\": \\\"[player]深吸一口气,使出“潜龙勿用”,双掌缓缓推出,看似平淡无奇,实则暗藏汹涌,击向[target]的腹部\\\"}\\n{\\\"招式\\\": \\\"挑字诀\\\", \\\"description\\\": \\\"[player]手中竹棒突然挑起,一招“挑字诀”,将[target]手中的兵刃高高挑起,使其失去攻击能力。\\\", \\\"missing\\\": \\\"[player]手中竹棒突然挑起,一招“挑字诀”,将[target]手中的兵刃高高挑起,使其失去攻击能力。\\\"}\\n{\\\"招式\\\": \\\"戳字诀\\\", \\\"description\\\": \\\"[player]手中竹棒迅速向前戳出,一招“戳字诀”,直指[target]的要害部位,使其无法闪避。\\\", \\\"missing\\\": \\\"[player]手中竹棒迅速向前戳出,一招“戳字诀”,直指[target]的要害部位,使其无法闪避。\\\"}\\n{\\\"招式\\\": \\\"劈字诀\\\", \\\"description\\\": \\\"[player]手中竹棒用力挥出,一招“劈字诀”,将[target]的防御破开,露出其脆弱的内部。\\\", \\\"missing\\\": \\\"[player]手中竹棒用力挥出,一招“劈字诀”,将[target]的防御破开,露出其脆弱的内部。\\\"}\\n{\\\"招式\\\": \\\"扫字诀\\\", \\\"description\\\": \\\"[player]手中竹棒横扫而出,一招“扫字诀”,将[target]逼退数步,使其无法靠近。\\\", \\\"missing\\\": \\\"[player]手中竹棒横扫而出,一招“扫字诀”,将[target]逼退数步,使其无法靠近。\\\"}\\n\"}\n",
178 | "{\"name\": \"令狐冲\", \"attr_str\": \"{\\\"name\\\": \\\"令狐冲\\\", \\\"description\\\": \\\"生性放荡不羁,有高度的忠义心,绝技有独孤九剑和吸星大法\\\", \\\"weapon\\\": \\\"剑\\\", \\\"major_martial_art\\\": \\\"独孤九剑\\\", \\\"major_movements\\\": [\\\"独孤九剑破剑式\\\", \\\"独孤九剑总诀式\\\", \\\"独孤九剑破气式\\\", \\\"独孤九剑破刀式\\\"], \\\"major_damage\\\": 70, \\\"secondary_martial_art\\\": \\\"吸星大法\\\", \\\"secondary_movements\\\": [\\\"吸星引\\\", \\\"化星诀\\\", \\\"星爆术\\\", \\\"星护盾\\\"], \\\"secondary_damage\\\": 80, \\\"footwork_and_body_method\\\": \\\"逍遥游\\\", \\\"STR\\\": 10, \\\"VIT\\\": 3, \\\"SPD\\\": 20}\", \"skills\": \"{\\\"招式\\\": \\\"独孤九剑破剑式\\\", \\\"description\\\": \\\"[player]运起独孤九剑的破剑式,剑意流转,直指[target]的剑路,破其剑势\\\", \\\"missing\\\": \\\"[player]运起独孤九剑的破剑式,剑意流转,直指[target]的剑路,试图破其剑势\\\"}\\n{\\\"招式\\\": \\\"独孤九剑总诀式\\\", \\\"description\\\": \\\"[player]使出独孤九剑的总诀式,剑招连绵不绝,如水银泻地,无孔不入,令[target]应接不暇\\\", \\\"missing\\\": \\\"[player]使出独孤九剑的总诀式,剑招连绵不绝,如水银泻地,无孔不入,向[target]攻去\\\"}\\n{\\\"招式\\\": \\\"独孤九剑破气式\\\", \\\"description\\\": \\\"[player]运起独孤九剑的破气式,剑意内敛,以无形剑气破[target]的内力,使其内息紊乱\\\", \\\"missing\\\": \\\"[player]运起独孤九剑的破气式,剑意内敛,以无形剑气破[target]的内力,试图使其内息紊乱\\\"}\\n{\\\"招式\\\": \\\"独孤九剑破刀式\\\", \\\"description\\\": \\\"[player]使出独孤九剑的破刀式,剑招轻灵,专克刀法,将[target]的刀路尽数封死\\\", \\\"missing\\\": \\\"[player]使出独孤九剑的破刀式,剑招轻灵,专克刀法,试图将[target]的刀路尽数封死\\\"}\\n{\\\"招式\\\": \\\"吸星引\\\", \\\"description\\\": \\\"[player]运起“吸星引”,双掌向前推出,一股强大的吸力将[target]拉至身前,随即运功吸取其内力\\\", \\\"missing\\\": \\\"[player]运起“吸星引”,双掌向前推出,一股强大的吸力将[target]拉至身前,随即运功吸取其内力\\\"}\\n{\\\"招式\\\": \\\"化星诀\\\", \\\"description\\\": \\\"[player]运起“化星诀”,将吸取到的内力转化为自身内力,增强自身实力\\\", \\\"missing\\\": \\\"[player]运起“化星诀”,将吸取到的内力转化为自身内力,增强自身实力\\\"}\\n{\\\"招式\\\": \\\"星爆术\\\", \\\"description\\\": \\\"[player]运起“星爆术”,将自身内力凝聚成一颗能量球,瞬间轰向[target],威力惊人\\\", \\\"missing\\\": \\\"[player]运起“星爆术”,将自身内力凝聚成一颗能量球,瞬间轰向[target],威力惊人\\\"}\\n{\\\"招式\\\": \\\"星护盾\\\", \\\"description\\\": \\\"[player]运起“星护盾”,将内力凝聚成一道护盾,抵挡来自[target]的攻击\\\", \\\"missing\\\": \\\"[player]运起“星护盾”,将内力凝聚成一道护盾,抵挡来自[target]的攻击\\\"}\\n\"}\n",
179 | "Keyboard interruption in main thread... closing server.\n",
180 | "Killing tunnel 0.0.0.0:7860 <> https://82acbd8c5d771378a4.gradio.live\n"
181 | ]
182 | },
183 | {
184 | "output_type": "execute_result",
185 | "data": {
186 | "text/plain": []
187 | },
188 | "metadata": {},
189 | "execution_count": 5
190 | }
191 | ],
192 | "source": [
193 | "import os\n",
194 | "\n",
195 | "os.environ[\"OPENAI_API_BASE\"] = \"https://api.sic/v1\"\n",
196 | "os.environ[\"OPENAI_API_KEY\"] = \"sk-szm0dCb096d3050\"\n",
197 | "os.environ[\"PG_CONNECTION_STRING\"] = \"postgres://postgres:8YyHzJ89W.223.30.145:5432/postgres\"\n",
198 | "\n",
199 | "from langchain.chat_models import ChatOpenAI\n",
200 | "from langchain.schema import (\n",
201 | " AIMessage,\n",
202 | " HumanMessage,\n",
203 | " SystemMessage\n",
204 | ")\n",
205 | "\n",
206 | "smart_system_prompt = \"\"\"You are ChatGPT, a large language model trained by OpenAI.\n",
207 | "Knowledge cutoff: 2021-09\n",
208 | "Current date: 2023-03-15\"\"\"\n",
209 | "\n",
210 | "ma_foo_answer = \"\"\"李鲁鲁,山东逍遥派的游戏角色,擅长人工智能傀儡术,以下是为你设计的两套武功和一套身法(招架)以及每套的四个招式名字:\n",
211 | "武功一:电脑幻影拳法\n",
212 | "这套武功利用人工智能傀儡术,创建虚拟幻影来欺骗对手,令其难以捉摸。\n",
213 | "电脑虚像拳 - 创造多个虚像,使对手难以分辨真伪。\n",
214 | "数据掌控击 - 利用数据流动的速度来快速攻击对手。\n",
215 | "模拟迷雾拳 - 释放模糊幻影,混淆对手的视线。\n",
216 | "程序化拳法 - 不断变化的攻击组合,让对手无法预测。\n",
217 | "武功二:智能预测刀法\n",
218 | "这套武功充分利用你的智能傀儡术,通过对对手的行为进行分析和预测,达到精准打击的效果。\n",
219 | "预测之刃 - 准确地预测对手的下一步行动,发动致命一击。\n",
220 | "数据漩涡斩 - 利用对手的动向,将其引导至陷阱,然后发动猛烈攻击。\n",
221 | "算法刀舞 - 刀法如算法一般精准,快速地切入对手的防线。\n",
222 | "智能反击剑 - 反击对手的招式,使其付出惨痛的代价。\n",
223 | "身法(招架):数码幻影步\n",
224 | "这套身法让你能够迅速回避对手的攻击,同时保持对局掌握主动权。\n",
225 | "数码闪避 - 迅速移动,如数码般闪烁,躲避对手的攻击。\n",
226 | "傀儡幻影步 - 创造虚假的身影,使对手无法锁定你的位置。\n",
227 | "数据跃迁 - 在一瞬间跳跃到对手的盲点,出其不意。\n",
228 | "逍遥之法 - 以逍遥派的身法融入自然,消除敌人的攻击威胁。\n",
229 | "希望这些武功和身法(招架)可以为你的李鲁鲁角色增添一些游戏中的精彩元素!\n",
230 | "\"\"\"\n",
231 | "\n",
232 | "attr_foo_answer = \"\"\"{\"name\": \"李鲁鲁\",\"STR\":5,\"SPD\":5,\"VIT\":5,\"description\": \"山东逍遥派的李鲁鲁,擅长人工智能傀儡术,善于提前预测对方的行动进行战斗\",\"weapon\": \"无\",\"major_martial_art\": \"人工智能傀儡术\",\"major_movements\": [\"预测之眼\", \"智慧编织\", \"虚实交融\", \"机巧纠缠\"],\"secondary_martial_art\": \"人工智能傀儡术\",\"secondary_movements\": [\"预测之眼\", \"智慧编织\", \"虚实交融\", \"机巧纠缠\"],\"footwork_and_body_method\": \"山水行云\"}\"\"\"\n",
233 | "\n",
234 | "attr_lilulu = \"\"\"{\n",
235 | " \"name\": \"李鲁鲁\",\n",
236 | " \"description\": \"山东逍遥派的游戏角色,擅长人工智能傀儡术\",\n",
237 | " \"weapon\": \"智能刀剑\",\n",
238 | " \"major_martial_art\": \"电脑幻影拳法\",\n",
239 | " \"major_movements\": [\"电脑虚像拳\", \"数据掌控击\", \"模拟迷雾拳\", \"程序化拳法\"],\n",
240 | " \"major_damage\": 75,\n",
241 | " \"secondary_martial_art\": \"智能预测刀法\",\n",
242 | " \"secondary_movements\": [\"预测之刃\", \"数据漩涡斩\", \"算法刀舞\", \"智能反击剑\"],\n",
243 | " \"secondary_damage\": 85,\n",
244 | " \"footwork_and_body_method\": \"数码幻影步\",\n",
245 | " \"STR\": 6,\n",
246 | " \"VIT\": 5,\n",
247 | " \"SPD\": 18\n",
248 | "}\n",
249 | "\"\"\"\n",
250 | "\n",
251 | "attr_lengziang = \"\"\"{\n",
252 | " \"name\": \"冷子昂\",\n",
253 | " \"description\": \"擅长冰系技能\",\n",
254 | " \"weapon\": \"冰刃\",\n",
255 | " \"major_martial_art\": \"冰霜寒刃功\",\n",
256 | " \"major_movements\": [\"冰刃斩破\", \"冰风流转\", \"冰龙穿云\", \"冰心彻骨\"],\n",
257 | " \"major_damage\": 80,\n",
258 | " \"secondary_martial_art\": \"冰封无影步\",\n",
259 | " \"secondary_movements\": [\"冰封幻影\", \"无影冻结\", \"冰刃闪耀\", \"冰封禅定\"],\n",
260 | " \"secondary_damage\": 70,\n",
261 | " \"footwork_and_body_method\": \"冰心护身法\",\n",
262 | " \"STR\": 8,\n",
263 | " \"VIT\": 6,\n",
264 | " \"SPD\": 15\n",
265 | "}\n",
266 | "\"\"\"\n",
267 | "\n",
268 | "json_str_huangrong = \"\"\"{\n",
269 | " \"name\": \"黄蓉\",\n",
270 | " \"description\": \"丐帮帮主黄蓉,擅长打狗棒法和落英神剑掌,身法为逍遥游。\",\n",
271 | " \"weapon\": \"棒、剑\",\n",
272 | " \"major_martial_art\": \"打狗棒法\",\n",
273 | " \"major_movements\": [\"狗啸山林\", \"棒影重重\", \"狗尾续貂\", \"狗急跳墙\"],\n",
274 | " \"major_damage\": 90,\n",
275 | " \"secondary_martial_art\": \"落英神剑掌\",\n",
276 | " \"secondary_movements\": [\"落英如雨\", \"神剑破空\", \"飞花流水\", \"剑指苍穹\"],\n",
277 | " \"secondary_damage\": 80,\n",
278 | " \"footwork_and_body_method\": \"逍遥游\",\n",
279 | " \"STR\": 15,\n",
280 | " \"VIT\": 10,\n",
281 | " \"SPD\": 18\n",
282 | "}\"\"\"\n",
283 | "\n",
284 | "skill_foo_desc = \"\"\"\n",
285 | "{\"招式\":\"预测之眼\",\"description\":\"[player]凝神聚气,双眼闪烁着深邃的智慧,一招“预测之眼”发动,仿佛未来已经显现在眼前,[player]能够精准预测[target]的下一步动作。\",\"missing\":\"[player]凝神聚气,双眼闪烁着深邃的智慧,一招“预测之眼”发动,仿佛未来已经显现在眼前,[target]的一举一动变得难以捉摸。\"}\n",
286 | "{\"招式\":\"智慧编织\",\"description\":\"[player]手中的线缠绕着[target],编织成一个巧妙的陷阱,一招“智慧编织”完成,如同织女编织云锦,[target]的行动受到了限制。\",\"missing\":\"[player]手中的线缠绕着,编织成一个巧妙的陷阱,一招“智慧编织”完成,[target]似乎被某种力量限制住了行动。\"}\n",
287 | "{\"招式\":\"虚实交融\",\"description\":\"[player]身形忽明忽暗,虚实难辨,一招“虚实交融”使出,仿佛有数个[player]一同出招,[target]不知所措。\",\"missing\":\"[player]身形忽明忽暗,虚实难辨,一招“虚实交融”使出,[target]眼前忽然出现了一片幻影,令其感到迷茫。\"}\n",
288 | "{\"招式\":\"机巧纠缠\",\"description\":\"[player]运用机巧傀儡术,手中的人工智能傀儡纷纷扑向[target],一招“机巧纠缠”展开,[target]被困在了傀儡的包围中。\",\"missing\":\"[player]运用机巧傀儡术,手中的人工智能傀儡纷纷扑向,一招“机巧纠缠”展开,[target]四面八方都是傀儡的身影,形势险恶。\"}\n",
289 | "{\"招式\":\"预测之眼\",\"description\":\"[player]凝神聚气,双眼闪烁着深邃的智慧,一招“预测之眼”发动,仿佛未来已经显现在眼前,[player]能够精准预测[target]的下一步动作。\",\"missing\":\"[player]凝神聚气,双眼闪烁着深邃的智慧,一招“预测之眼”发动,仿佛未来已经显现在眼前,[target]的一举一动变得难以捉摸。\"}\n",
290 | "{\"招式\":\"智慧编织\",\"description\":\"[player]手中的线缠绕着[target],编织成一个巧妙的陷阱,一招“智慧编织”完成,如同织女编织云锦,[target]的行动受到了限制。\",\"missing\":\"[player]手中的线缠绕着,编织成一个巧妙的陷阱,一招“智慧编织”完成,[target]似乎被某种力量限制住了行动。\"}\n",
291 | "{\"招式\":\"虚实交融\",\"description\":\"[player]身形忽明忽暗,虚实难辨,一招“虚实交融”使出,仿佛有数个[player]一同出招,[target]不知所措。\",\"missing\":\"[player]身形忽明忽暗,虚实难辨,一招“虚实交融”使出,[target]眼前忽然出现了一片幻影,令其感到迷茫。\"}\n",
292 | "{\"招式\":\"机巧纠缠\",\"description\":\"[player]运用机巧傀儡术,手中的人工智能傀儡纷纷扑向[target],一招“机巧纠缠”展开,[target]被困在了傀儡的包围中。\",\"missing\":\"[player]运用机巧傀儡术,手中的人工智能傀儡纷纷扑向,一招“机巧纠缠”展开,[target]四面八方都是傀儡的身影,形势险恶。\"}\n",
293 | "\"\"\"\n",
294 | "\n",
295 | "skill_lilulu = \"\"\"\n",
296 | "{\"招式\":\"电脑虚像拳\",\"description\":\"[player]运用电脑幻影拳法,双拳虚虚实实,制造出多个虚像,令[target]难以分辨真伪,招招不离其身。\",\"missing\":\"[player]运用电脑幻影拳法,双拳虚虚实实,制造出多个虚像,令[target]难以分辨真伪。\"}\n",
297 | "{\"招式\":\"数据掌控击\",\"description\":\"[player]施展数据掌控击,利用数据流动的速度,犹如电光闪烁,快速攻击[target],剑招迅猛,如电一般。\",\"missing\":\"[player]施展数据掌控击,利用数据流动的速度,犹如电光闪烁,快速攻击[target],剑招迅猛。\"}\n",
298 | "{\"招式\":\"模拟迷雾拳\",\"description\":\"[player]施展模拟迷雾拳,释放出模糊幻影,混淆[target]的视线,令其难以辨别攻击方向。\",\"missing\":\"[player]施展模拟迷雾拳,释放出模糊幻影,混淆[target]的视线,令其难以辨别攻击方向。\"}\n",
299 | "{\"招式\":\"程序化拳法\",\"description\":\"[player]运用程序化拳法,以不断变化的攻击组合,让[target]难以预测招式,时而快时而慢,攻击变幻莫测。\",\"missing\":\"[player]运用程序化拳法,以不断变化的攻击组合,让[target]难以预测招式,攻击变幻莫测。\"}\n",
300 | "{\"招式\":\"预测之刃\",\"description\":\"[player]使出预测之刃,准确地预测[target]的下一步行动,犹如镜中水月,剑锋准确地击中[target]的要害。\",\"missing\":\"[player]使出预测之刃,准确地预测[target]的下一步行动,犹如镜中水月,剑锋迅速挥出。\"}\n",
301 | "{\"招式\":\"数据漩涡斩\",\"description\":\"[player]施展数据漩涡斩,利用[target]的动向,将其引导至剑刃之下,然后发动猛烈攻击,犹如漩涡将[target]吸入其中。\",\"missing\":\"[player]施展数据漩涡斩,利用[target]的动向,将其引导至剑刃之下,然后发动猛烈攻击,剑招异常犀利。\"}\n",
302 | "{\"招式\":\"算法刀舞\",\"description\":\"[player]挥舞着长剑,使出算法刀舞,刀法如算法一般精准,快速地切入[target]的防线,剑锋连续不断地斩向[target]。\",\"missing\":\"[player]挥舞着长剑,使出算法刀舞,刀法如算法一般精准,快速地切入[target]的防线,剑招变化多端。\"}\n",
303 | "{\"招式\":\"智能反击剑\",\"description\":\"[player]运用智能反击剑,反击[target]的招式,使其付出惨痛的代价,一瞬间的犹豫就足以让[target]受伤。\",\"missing\":\"[player]运用智能反击剑,反击[target]的招式,使其陷入困境,一瞬间的犹豫足以让[target]付出代价。\"}\n",
304 | "\"\"\"\n",
305 | "\n",
306 | "skill_lengziang = \"\"\"\n",
307 | "{\"招式\":\"冰刃斩破\",\"description\":\"[player]聚集冰之力量于剑上,使出冰刃斩破,剑锋犹如寒冰之刃斩向[target]的要害部位,寒气逼人,剑光炽烈。\",\"missing\":\"[player]聚集冰之力量于剑上,使出冰刃斩破,剑锋犹如寒冰之刃,闪电般挥出。\"}\n",
308 | "{\"招式\":\"冰风流转\",\"description\":\"[player]身体如风一般旋转,同时释放出冰风刃,打击周围的敌人,冷飕飕的寒风环绕,[target]身不由己地被吹向一旁。\",\"missing\":\"[player]身体如风一般旋转,同时释放出冰风刃,冷飕飕的寒风环绕,风刃在[target]周围飞舞。\"}\n",
309 | "{\"招式\":\"冰龙穿云\",\"description\":\"[player]召唤出一条冰龙,冰龙穿越云层直扑[target],寒冰之力凝聚在龙爪之上,将[target]冻结一切,一切都难以抵挡。\",\"missing\":\"[player]召唤出一条冰龙,冰龙穿越云层,龙爪直扑[target],寒冰之力凝聚在龙爪之上,寒意森然。\"}\n",
310 | "{\"招式\":\"冰心彻骨\",\"description\":\"[player]凝聚冰之力于手,一触即可让[target]骨骼寒冷,动弹不得,彻底冰封,剑锋轻轻触及[target],寒意透骨。\",\"missing\":\"[player]凝聚冰之力于手,一触即可让[target]骨骼寒冷,动弹不得,寒气透骨,剑锋轻轻触及[target]。\"}\n",
311 | "{\"招式\":\"冰封幻影\",\"description\":\"[player]运用冰封无影步,快速移动,留下一道冰封的幻影,使[target]无法辨别真伪,幻影与实体交替出现,令[target]不知所措。\",\"missing\":\"[player]运用冰封无影步,快速移动,留下一道冰封的幻影,使[target]无法辨别真伪。\"}\n",
312 | "{\"招式\":\"无影冻结\",\"description\":\"[player]以极快的速度接近[target],然后冻结[target]的动作,使其陷入无法自拔的状态,如同身陷冰封之中,动弹不得。\",\"missing\":\"[player]以极快的速度接近[target],然后冻结[target]的动作,使其陷入无法自拔的状态。\"}\n",
313 | "{\"招式\":\"冰刃闪耀\",\"description\":\"[player]利用冰之能量,瞬间闪现至[target]身边,发动迅猛的攻击,剑锋如星光般闪烁,将[target]包围其中。\",\"missing\":\"[player]利用冰之能量,瞬间闪现至[target]身边,发动迅猛的攻击,剑锋如星光般闪烁。\"}\n",
314 | "{\"招式\":\"冰封禅定\",\"description\":\"[player]静心冥想,将身体冰封,使自己无法被[target]察觉,达到不可捉摸的状态,如同融入冰封禅定之中。\",\"missing\":\"[player]静心冥想,将身体冰封,使自己无法被[target]察觉,达到不可捉摸的状态。\"}\n",
315 | "\"\"\"\n",
316 | "\n",
317 | "skill_huangrong = \"\"\"\n",
318 | "{\"招式\": \"狗啸山林\", \"description\": \"[player]手中长棒一挥,发出一声凄厉的狗啸,棒影如山林般扑向[target]\", \"missing\": \"[player]手中长棒一挥,发出一声凄厉的狗啸,棒影如山林般扑向[target]\"}\n",
319 | "{\"招式\": \"棒影重重\", \"description\": \"[player]身形连转,手中长棒化作无数道棒影,重重叠叠地向[target]砸去\", \"missing\": \"[player]身形连转,手中长棒化作无数道棒影,重重叠叠地向[target]砸去\"}\n",
320 | "{\"招式\": \"狗尾续貂\", \"description\": \"[player]手中长棒如狗尾续貂般灵动,连续变换方向,向[target]连续攻击\", \"missing\": \"[player]手中长棒如狗尾续貂般灵动,连续变换方向,向[target]连续攻击\"}\n",
321 | "{\"招式\": \"狗急跳墙\", \"description\": \"[player]猛地一跃,手中长棒带起狂风,如狗急跳墙般向[target]砸去\", \"missing\": \"[player]猛地一跃,手中长棒带起狂风,如狗急跳墙般向[target]砸去\"}\n",
322 | "{\"招式\": \"落英如雨\", \"description\": \"[player]身形一闪,双掌连续拍出,犹如漫天飘落的落英,掌风凌厉,瞬间覆盖[target]周身\", \"missing\": \"[player]身形一闪,双掌连续拍出,犹如漫天飘落的落英,掌风凌厉,向[target]周身袭去\"}\n",
323 | "{\"招式\": \"神剑破空\", \"description\": \"[player]手中剑光闪烁,一剑刺出,剑气凌厉无比,犹如神剑破开虚空,直指[target]要害\", \"missing\": \"[player]手中剑光闪烁,一剑刺出,剑气凌厉无比,直向[target]要害刺去\"}\n",
324 | "{\"招式\": \"飞花流水\", \"description\": \"[player]身形如飞,双掌连续拍击,掌风如流水般连绵不绝,将[target]团团围住\", \"missing\": \"[player]身形如飞,双掌连续拍击,掌风如流水般连绵不绝,向[target]团团包围\"}\n",
325 | "{\"招式\": \"剑指苍穹\", \"description\": \"[player]手中长剑一指,剑光直冲云霄,气势如虹,剑指直指苍穹,威力惊人\", \"missing\": \"[player]手中长剑一指,剑光直冲云霄,气势如虹,直指苍穹\"}\n",
326 | "\"\"\"\n",
327 | "\n",
328 | "\n",
329 | "def generate_detailed_description(name, description):\n",
330 | " task_message = f\"\"\"我的名字叫“{name}”,假设我是一个武侠中的游戏角色,{description}\n",
331 | " 请基于我的名字和门派,先为我设计2套武功和一套身法或者招架。\n",
332 | " 再为每套武功设计4个对应招式的名字。\"\"\"\n",
333 | "\n",
334 | " # messages = [\n",
335 | " # SystemMessage(content=smart_system_prompt),\n",
336 | " # HumanMessage(content=task_message),\n",
337 | " # ]\n",
338 | "\n",
339 | " messages = \"System message: \" + smart_system_prompt + \"\\nUser: \" + task_message\n",
340 | "\n",
341 | " # chat = ChatOpenAI(model=\"gpt-3.5-turbo\", temperature=0.3)\n",
342 | "\n",
343 | " response = chat_baichuan(messages)\n",
344 | " return response\n",
345 | "\n",
346 | "\n",
347 | "def generate_attr_json(name, description, detailed_description):\n",
348 | " task_message = f\"\"\"我正在为我的武侠游戏设计人物。给定一个人物和这个人物的背景描述(可选)\n",
349 | "我希望你根据这个人物的背景和名字以及输入的suggestion信息,为我生成这个人的资料,以json的格式输出,包括\n",
350 | "description: 这个角色的背景等信息\n",
351 | "weapon: 这个人使用的武器种类,\n",
352 | "major_martial_art: 这个人的主要武学\n",
353 | "major_movements: 这个人主要武学的4个对应招式的名字。招式的名字需要尽可能和major_martial_art有关。movements的名字尽量不要使用重复的文字。可以使用形象的动作或者是一些动物的比喻。\n",
354 | "major_damage: 主武学的威力,50到150之间的整数。重视速度的功法威力会低一些。重视攻击的功法威力会高一些\n",
355 | "secondary_movements: 这个角色的次要武学\n",
356 | "secondary_movements: 这个人次要武学的4个对应招式的名字。招式的名字需要尽可能和secondary_movements有关\n",
357 | "secondary_damage: 次要武学的威力,50到150之间的整数。\n",
358 | "footwork_and_body_method: 这个角色的轻功或者防御功法\n",
359 | "STR: 角色的攻击力, 0-20之间的整数\n",
360 | "VIT: 角色的体质, 0-20之间的整数\n",
361 | "SPD: 角色的速度,0-20之间的整数\n",
362 | "\"\"\"\n",
363 | " example_input = \"\"\"example_input:\n",
364 | "name: 令狐冲\n",
365 | "description: -\n",
366 | "suggestion:-\"\"\"\n",
367 | "\n",
368 | " example_output = \"\"\"example_output:\n",
369 | "{\n",
370 | " \"name\": \"令狐冲\",\n",
371 | " \"description\": \"华山派的大师兄\",\n",
372 | " \"weapon\": \"剑\",\n",
373 | " \"major_martial_art\": \"独孤九剑\",\n",
374 | " \"major_movements\": [\"独孤九剑破剑式\",\"独孤九剑总诀式\",\"独孤九剑破气式\",\"独孤九剑破刀式\"],\n",
375 | " \"major_damage\": 70,\n",
376 | " \"secondary_martial_art\": \"华山剑法\",\n",
377 | " \"secondary_movements\": [\"有凤来仪\",\"飞沙走石\",\"百丈飞瀑\",\"青山隐隐\"],\n",
378 | " \"secondary_damage\":80,\n",
379 | " \"footwork_and_body_method\": \"华山身法\",\n",
380 | " \"STR\":10,\n",
381 | " \"VIT\":3,\n",
382 | " \"SPD\":20\n",
383 | "}\"\"\"\n",
384 | "\n",
385 | " input = f\"\"\"input:\n",
386 | "name: {name},\n",
387 | "description: {description},\n",
388 | "suggestion: `{detailed_description}`\n",
389 | " \"\"\"\n",
390 | "\n",
391 | " # messages = [\n",
392 | " # SystemMessage(content=smart_system_prompt),\n",
393 | " # HumanMessage(content=task_message),\n",
394 | " # HumanMessage(content=example_input),\n",
395 | " # AIMessage(content=example_output),\n",
396 | " # HumanMessage(content=input)]\n",
397 | " messages = \"System message: \" + smart_system_prompt + \"\\nUser: \" + task_message + \"\\nUser: \" + example_input + \"\\nAI: \" + example_output + \"\\nUser: \" + input\n",
398 | "\n",
399 | " # chat = ChatOpenAI(model=\"gpt-3.5-turbo\", temperature=0.1)\n",
400 | "\n",
401 | " response = chat_baichuan(messages)\n",
402 | " return response\n",
403 | "\n",
404 | "\n",
405 | "import json\n",
406 | "\n",
407 | "\n",
408 | "def robust_parsing(input_str):\n",
409 | " try:\n",
410 | " return json.loads(input_str)\n",
411 | " except json.JSONDecodeError:\n",
412 | " start = input_str.find('{')\n",
413 | " end = input_str.rfind('}') + 1\n",
414 | " if start != -1 and end != -1:\n",
415 | " try:\n",
416 | " return json.loads(input_str[start:end])\n",
417 | " except json.JSONDecodeError:\n",
418 | " pass\n",
419 | "\n",
420 | " return None\n",
421 | "\n",
422 | "\n",
423 | "def generate_skill_detail(martial_art_name, movements):\n",
424 | " task_message = \"\"\"现在我希望你根据武侠小说中的武功和招式的名字。为招式补全合理的description和missing描述。\n",
425 | "在description的描述中,player可以击中目标,可以有兵器撞击声响等描述。\n",
426 | "在missing描述中,player并不一定击中目标,不可以有击落、击中、夺去这样的描述\n",
427 | "在用[player]代表技能的使用者,用[target]代表技能的目标。结果需用合理的jsonl格式展示,下面是一个例子。\"\"\"\n",
428 | "\n",
429 | " example_input = \"\"\"example input:\n",
430 | "martial_art_name = 华山剑法\n",
431 | "{\"招式\":\"百丈飞瀑\"}\n",
432 | "{\"招式\":\"百鸟朝凤\"}\n",
433 | "{\"招式\":\"青山隐隐\"}\n",
434 | "{\"招式\":\"飞沙走石\"}\"\"\"\n",
435 | "\n",
436 | " example_output = \"\"\"example output:\n",
437 | "{\"招式\":\"百丈飞瀑\",\"description\":\"[player]翻身回剑,剑诀斜引,一招“百丈飞瀑”,剑锋从半空中直泻下来\",\"missing\":\"[player]一咬牙,翻身回剑,剑诀斜引,一招“百丈飞瀑”,剑锋从半空中直泻下来\"}\n",
438 | "{\"招式\":\"百鸟朝凤\",\"description\":\"[player]长剑一起,使一招“百鸟朝凤”,但见剑尖乱颤,霎时间便如化为数十个剑尖,罩住[target]中盘\",\"missing\":\"[player]使一招“百鸟朝凤”,但见剑尖乱颤,霎时间便如化为数十个剑尖,向[target]飞去\"}\n",
439 | "{\"招式\":\"青山隐隐\", \"description\":\"[player]吸一口气,长剑中宫直进,剑尖不住颤动,剑到中途,忽然转而向上,乃是一招“青山隐隐”,端的是若有若无,变幻无方。\",\"missing\":\"[player]吸一口气,长剑中宫直进,剑尖不住颤动,剑到中途,忽然转而向上,乃是一招“青山隐隐”,端的是若有若无,变幻无方。\"}\n",
440 | "{\"招式\":\"飞沙走石\", \"description\":\"长剑挺起,使一招“飞沙走石”,内劲直贯剑尖,寒光点点,挡的一声,击中的[target]胸口。\",\"missing\":\"长剑挺起,使一招“飞沙走石”,内劲直贯剑尖,寒光点点,直向[target]胸口刺去。\"}\"\"\"\n",
441 | "\n",
442 | " input = \"input:\\nmartial_art_name = \" + martial_art_name + \"\\n\"\n",
443 | " for m in movements:\n",
444 | " input += f\"\"\"{{\"招式\":\"{m}\"\\}}\\n\"\"\"\n",
445 | "\n",
446 | " # messages = [\n",
447 | " # SystemMessage(content=smart_system_prompt),\n",
448 | " # HumanMessage(content=task_message),\n",
449 | " # HumanMessage(content=example_input),\n",
450 | " # AIMessage(content=example_output),\n",
451 | " # HumanMessage(content=input)]\n",
452 | "\n",
453 | " messages = \"System message: \" + smart_system_prompt + \"\\nUser: \" + task_message + \"\\nUser: \" + example_input + \"\\nAI: \" + example_output + \"\\nUser: \" + input\n",
454 | "\n",
455 | " # chat = ChatOpenAI(model=\"gpt-3.5-turbo\", temperature=0.1)\n",
456 | "\n",
457 | " response = chat_baichuan(messages)\n",
458 | " return response\n",
459 | "\n",
460 | "\n",
461 | "def generate_skill_jsonl(json_data):\n",
462 | " major_skills = generate_skill_detail(json_data[\"major_martial_art\"], json_data[\"major_movements\"])\n",
463 | " secondary_skills = generate_skill_detail(json_data[\"secondary_martial_art\"], json_data[\"secondary_movements\"])\n",
464 | "\n",
465 | " all_skills = major_skills + \"\\n\" + secondary_skills\n",
466 | "\n",
467 | " ans = \"\"\n",
468 | "\n",
469 | " lines = all_skills.split(\"\\n\")\n",
470 | " for line in lines:\n",
471 | " json_data = robust_parsing(line)\n",
472 | " if json_data is not None:\n",
473 | " json_str = json.dumps(json_data, ensure_ascii=False)\n",
474 | " ans += json_str + \"\\n\"\n",
475 | "\n",
476 | " return ans\n",
477 | "\n",
478 | "\n",
479 | "import random\n",
480 | "\n",
481 | "\n",
482 | "class Player:\n",
483 | " def __init__(self, attr_json, skill_jsonl):\n",
484 | " self.name = attr_json[\"name\"]\n",
485 | " self.STR = attr_json[\"STR\"]\n",
486 | " self.SPD = attr_json[\"SPD\"]\n",
487 | " self.VIT = attr_json[\"VIT\"]\n",
488 | " if \"major_damage\" in attr_json:\n",
489 | " self.major_damage = attr_json[\"major_damage\"]\n",
490 | " else:\n",
491 | " self.major_damage = 65\n",
492 | "\n",
493 | " if \"secondary_damage\" in attr_json:\n",
494 | " self.secondary_damage = attr_json[\"secondary_damage\"]\n",
495 | " else:\n",
496 | " self.secondary_damage = 50\n",
497 | "\n",
498 | " self.normalize_attr()\n",
499 | " if \"hp\" in attr_json:\n",
500 | " self.hp = attr_json[\"hp\"]\n",
501 | " else:\n",
502 | " self.hp = (self.VIT + 10) * 15\n",
503 | "\n",
504 | " if \"skills\" in attr_json:\n",
505 | " self.skills = attr_json[\"skills\"]\n",
506 | " else:\n",
507 | " self.skills = self.parsing_skill(skill_jsonl)\n",
508 | "\n",
509 | " self.original_json = attr_json\n",
510 | "\n",
511 | " def normalize_attr(self):\n",
512 | " max_attr_value = 20\n",
513 | " min_attr_value = 0\n",
514 | " regular_attr_sum = 30\n",
515 | " xs = [self.STR, self.SPD, self.VIT]\n",
516 | " current_sum = 0\n",
517 | " for i in range(3):\n",
518 | " xs[i] = min(max_attr_value, xs[i])\n",
519 | " xs[i] = max(min_attr_value, xs[i])\n",
520 | " current_sum += xs[i]\n",
521 | "\n",
522 | " if current_sum > regular_attr_sum:\n",
523 | " for i in range(3):\n",
524 | " xs[i] = round(xs[i] * regular_attr_sum / current_sum)\n",
525 | " elif current_sum < regular_attr_sum:\n",
526 | " for i in range(3):\n",
527 | " xs[i] = round(xs[i] * regular_attr_sum / current_sum)\n",
528 | "\n",
529 | " random_i = random.randint(0, 2)\n",
530 | " xs[random_i] = xs[random_i] + regular_attr_sum - sum(xs)\n",
531 | "\n",
532 | " self.STR = xs[0]\n",
533 | " self.SPD = xs[1]\n",
534 | " self.VIT = xs[2]\n",
535 | "\n",
536 | " def get_new_json(self):\n",
537 | " new_json = self.original_json\n",
538 | " new_json[\"STR\"] = self.STR\n",
539 | " new_json[\"SPD\"] = self.SPD\n",
540 | " new_json[\"VIT\"] = self.VIT\n",
541 | " new_json[\"hp\"] = self.hp\n",
542 | " new_json[\"skills\"] = self.skills\n",
543 | " return new_json\n",
544 | "\n",
545 | " def parsing_skill(self, skill_jsonl):\n",
546 | " skills = []\n",
547 | " lines = skill_jsonl.split(\"\\n\")\n",
548 | " for line in lines:\n",
549 | " if line.strip() == \"\":\n",
550 | " continue\n",
551 | " skill = json.loads(line)\n",
552 | " skills.append(skill)\n",
553 | " return skills\n",
554 | "\n",
555 | "damage_bias = [-4, -6, 0, 10, -4, -6, 0, 10]\n",
556 | "\n",
557 | "hit_map = {30: 131, 31: 131, 32: 131, 33: 131, 34: 131, 35: 120, 36: 112, 37: 107, 38: 103, 39: 100, 40: 97, 41: 95,\n",
558 | " 42: 93, 43: 91, 44: 89, 45: 87, 46: 86, 47: 85, 48: 83, 49: 82, 50: 81, 51: 80, 52: 79, 53: 78, 54: 77,\n",
559 | " 55: 76, 56: 75, 57: 74, 58: 73, 59: 72, 60: 71, 61: 70, 62: 69, 63: 69, 64: 68, 65: 67, 66: 66, 67: 65,\n",
560 | " 68: 65, 69: 64, 70: 63, 71: 63, 72: 62, 73: 61, 74: 61, 75: 60, 76: 59, 77: 59, 78: 58, 79: 58, 80: 57,\n",
561 | " 81: 57, 82: 56, 83: 55, 84: 55, 85: 54, 86: 54, 87: 53, 88: 53, 89: 52, 90: 52, 91: 52, 92: 51, 93: 51,\n",
562 | " 94: 50, 95: 50, 96: 49, 97: 49, 98: 49, 99: 48, 100: 48, 101: 47, 102: 47, 103: 47, 104: 46, 105: 46,\n",
563 | " 106: 46, 107: 45, 108: 45, 109: 44, 110: 44, 111: 44, 112: 43, 113: 43, 114: 43, 115: 43, 116: 42, 117: 42,\n",
564 | " 118: 42, 119: 41, 120: 41, 121: 41, 122: 40, 123: 40, 124: 40, 125: 40, 126: 39, 127: 39, 128: 39, 129: 39,\n",
565 | " 130: 38, 131: 38, 132: 38, 133: 38, 134: 37, 135: 37, 136: 37, 137: 37, 138: 36, 139: 36, 140: 36, 141: 36,\n",
566 | " 142: 36, 143: 35, 144: 35, 145: 35, 146: 35, 147: 34, 148: 34, 149: 34, 150: 34, 151: 34, 152: 33, 153: 33,\n",
567 | " 154: 33, 155: 33, 156: 33, 157: 33, 158: 32, 159: 32, 160: 32, 161: 32, 162: 32, 163: 31, 164: 31, 165: 31,\n",
568 | " 166: 31, 167: 31, 168: 31, 169: 30, 170: 30, 171: 30, 172: 30, 173: 30, 174: 30, 175: 30, 176: 29, 177: 29,\n",
569 | " 178: 29, 179: 29, 180: 29}\n",
570 | "\n",
571 | "min_damage = 34\n",
572 | "max_damage = 180\n",
573 | "\n",
574 | "\n",
575 | "class GameManager:\n",
576 | " def __init__(self, attr_json1, attr_json2, skill_jsonl1, skill_jsonl2):\n",
577 | " self.player1 = Player(attr_json1, skill_jsonl1)\n",
578 | " self.player2 = Player(attr_json2, skill_jsonl2)\n",
579 | "\n",
580 | " def run(self):\n",
581 | " speed_diff = self.player1.SPD - self.player2.SPD\n",
582 | " if speed_diff == 0:\n",
583 | " speed_diff = random.randint(0, 3) * 2 - 3\n",
584 | "\n",
585 | " skill_id_1 = random.randint(0, len(self.player1.skills) - 1)\n",
586 | " dmg_1 = 60\n",
587 | " if skill_id_1 + skill_id_1 < len(self.player1.skills):\n",
588 | " dmg_1 = self.player1.major_damage\n",
589 | " else:\n",
590 | " dmg_1 = self.player1.secondary_damage\n",
591 | "\n",
592 | " dmg_1 += damage_bias[skill_id_1]\n",
593 | "\n",
594 | " skill_1_to_2 = self.player1.skills[skill_id_1]\n",
595 | " skill_1_to_2[\"dmg\"] = dmg_1\n",
596 | "\n",
597 | " # print(dmg_1)\n",
598 | "\n",
599 | " skill_id_2 = random.randint(0, len(self.player2.skills) - 1)\n",
600 | " dmg_2 = 60\n",
601 | " if skill_id_2 + skill_id_2 < len(self.player2.skills):\n",
602 | " dmg_2 = self.player2.major_damage\n",
603 | " else:\n",
604 | " dmg_2 = self.player2.secondary_damage\n",
605 | "\n",
606 | " dmg_2 += damage_bias[skill_id_2]\n",
607 | "\n",
608 | " skill_2_to_1 = self.player2.skills[skill_id_2]\n",
609 | " skill_2_to_1[\"dmg\"] = dmg_2\n",
610 | "\n",
611 | " # skill_2_to_1 = random.choice(self.player2.skills)\n",
612 | "\n",
613 | " # print(skill_1_to_2)\n",
614 | " # print(skill_2_to_1)\n",
615 | "\n",
616 | " damage_1_to_2 = self.compute_damage(skill_1_to_2, self.player1, self.player2)\n",
617 | " damage_2_to_1 = self.compute_damage(skill_2_to_1, self.player2, self.player1)\n",
618 | "\n",
619 | " ratio_1_to_2 = self.compute_ratio(skill_1_to_2, self.player1, self.player2)\n",
620 | " ratio_2_to_1 = self.compute_ratio(skill_2_to_1, self.player2, self.player1)\n",
621 | "\n",
622 | " if_hitted_1_to_2 = random.random() * 100.0 < ratio_1_to_2\n",
623 | " if_hitted_2_to_1 = random.random() * 100.0 < ratio_2_to_1\n",
624 | "\n",
625 | " desc_1_to_2 = skill_1_to_2[\"description\"] if if_hitted_1_to_2 else skill_1_to_2[\"missing\"]\n",
626 | " desc_1_to_2 = desc_1_to_2.replace(\"[player]\", self.player1.name).replace(\"[target]\", self.player2.name)\n",
627 | "\n",
628 | " if if_hitted_1_to_2:\n",
629 | " desc_1_to_2 += f\"造成了{round(damage_1_to_2)}的伤害。\"\n",
630 | " else:\n",
631 | " desc_1_to_2 += f\"{self.player2.name}躲了过去\"\n",
632 | "\n",
633 | " desc_2_to_1 = skill_2_to_1[\"description\"] if if_hitted_2_to_1 else skill_2_to_1[\"missing\"]\n",
634 | " desc_2_to_1 = desc_2_to_1.replace(\"[player]\", self.player2.name).replace(\"[target]\", self.player1.name)\n",
635 | " if if_hitted_2_to_1:\n",
636 | " desc_2_to_1 += f\"造成了{round(damage_2_to_1)}的伤害。\"\n",
637 | " else:\n",
638 | " desc_2_to_1 += f\"{self.player1.name}躲了过去\"\n",
639 | "\n",
640 | " self.flag = \"continue\"\n",
641 | "\n",
642 | " ans_msg = []\n",
643 | "\n",
644 | " if self.player2.hp <= 0:\n",
645 | " ans_msg.append((None, f\"{self.player2.name}战败了\"))\n",
646 | " return ans_msg, self.player1.get_new_json(), self.player2.get_new_json()\n",
647 | "\n",
648 | " if self.player1.hp <= 0:\n",
649 | " ans_msg.append((f\"{self.player1.name}战败了\", None))\n",
650 | " return ans_msg, self.player1.get_new_json(), self.player2.get_new_json()\n",
651 | "\n",
652 | " if speed_diff > 0:\n",
653 | " if if_hitted_1_to_2:\n",
654 | " self.player2.hp -= damage_1_to_2\n",
655 | "\n",
656 | " ans_msg.append((desc_1_to_2, None))\n",
657 | "\n",
658 | " if self.player2.hp > 0 and if_hitted_2_to_1:\n",
659 | " self.player1.hp -= damage_2_to_1\n",
660 | "\n",
661 | " if self.player2.hp > 0:\n",
662 | " ans_msg.append((None, desc_2_to_1))\n",
663 | "\n",
664 | " else:\n",
665 | " if if_hitted_2_to_1:\n",
666 | " self.player1.hp -= damage_2_to_1\n",
667 | "\n",
668 | " ans_msg.append((None, desc_2_to_1))\n",
669 | "\n",
670 | " if self.player1.hp > 0 and if_hitted_1_to_2:\n",
671 | " self.player2.hp -= damage_1_to_2\n",
672 | "\n",
673 | " if self.player1.hp > 0:\n",
674 | " ans_msg.append((desc_1_to_2, None))\n",
675 | "\n",
676 | " if self.player2.hp <= 0:\n",
677 | " ans_msg.append((None, f\"{self.player2.name}战败了\"))\n",
678 | " self.flag = \"player1_win\"\n",
679 | " if self.player1.hp <= 0:\n",
680 | " ans_msg.append((f\"{self.player1.name}战败了\", None))\n",
681 | " self.flag = \"player2_win\"\n",
682 | "\n",
683 | " return ans_msg, self.player1.get_new_json(), self.player2.get_new_json()\n",
684 | "\n",
685 | " # default \"damage\": 60, \"hit\": 76,\n",
686 | " def compute_damage(self, skill, player, target):\n",
687 | " damage_ratio = skill[\"dmg\"]\n",
688 | " damage_ratio = max(min_damage, damage_ratio)\n",
689 | " damage_ratio = min(max_damage, damage_ratio)\n",
690 | " skill_damage = damage_ratio + player.STR * 2\n",
691 | " attack_diff = player.STR - target.VIT * 0.5\n",
692 | " damage = skill_damage * (1 + 0.95 * (-0.5 + 1.0 / (1.0 + exp(-attack_diff / 6.0))))\n",
693 | " return damage\n",
694 | "\n",
695 | " def compute_ratio(self, skill, player, target):\n",
696 | " damage_ratio = skill[\"dmg\"]\n",
697 | " damage_ratio = round(damage_ratio)\n",
698 | " damage_ratio = max(min_damage, damage_ratio)\n",
699 | " damage_ratio = min(max_damage, damage_ratio)\n",
700 | " skill_hit = hit_map[damage_ratio]\n",
701 | "\n",
702 | " speed_diff = player.SPD - target.SPD\n",
703 | " hit_factor = (-0.5 + 1.0 / (1.0 + exp(-speed_diff / 6.0))) / 2.0 * max(30.0, skill_hit)\n",
704 | " return hit_factor + skill_hit\n",
705 | "\n",
706 | "\n",
707 | "fighter_save_name = 'LuotuoFighter.txt'\n",
708 | "\n",
709 | "import os\n",
710 | "\n",
711 | "datas = []\n",
712 | "\n",
713 | "if not os.path.exists(fighter_save_name):\n",
714 | " data = {\n",
715 | " \"name\": \"李鲁鲁\",\n",
716 | " \"attr_str\": attr_lilulu,\n",
717 | " \"skills\": skill_lilulu\n",
718 | " }\n",
719 | " datas.append(data)\n",
720 | " data = {\n",
721 | " \"name\": \"冷子昂\",\n",
722 | " \"attr_str\": attr_lengziang,\n",
723 | " \"skills\": skill_lengziang\n",
724 | " }\n",
725 | " datas.append(data)\n",
726 | " data = {\n",
727 | " \"name\": \"黄蓉\",\n",
728 | " \"attr_str\": json_str_huangrong,\n",
729 | " \"skills\": skill_huangrong\n",
730 | " }\n",
731 | " datas.append(data)\n",
732 | " with open(fighter_save_name, 'w', encoding=\"utf-8\") as f:\n",
733 | " for data in datas:\n",
734 | " f.write(json.dumps(data, ensure_ascii=False) + \"\\n\")\n",
735 | "else:\n",
736 | " with open(fighter_save_name, 'r', encoding=\"utf-8\") as f:\n",
737 | " for line in f.readlines():\n",
738 | " data = json.loads(line)\n",
739 | " datas.append(data)\n",
740 | "\n",
741 | "fighter_data = datas\n",
742 | "\n",
743 | "elo_table = {}\n",
744 | "\n",
745 | "\n",
746 | "def get_unique_from_data(data):\n",
747 | " name = data[\"name\"]\n",
748 | " json_data = json.loads(data[\"attr_str\"])\n",
749 | " return get_unique_from_json(name, json_data)\n",
750 | "\n",
751 | "\n",
752 | "def get_unique_from_json(name, json_data):\n",
753 | " if \"STR\" in json_data and \"VIT\" in json_data and \"SPD\" in json_data and \"major_damage\" in json_data and \"secondary_damage\" in json_data:\n",
754 | " return name + \"_\" + str(json_data[\"major_damage\"]) + \"_\" + str(json_data[\"secondary_damage\"])\n",
755 | " else:\n",
756 | " return None\n",
757 | "\n",
758 | "unique_to_score = {}\n",
759 | "name_to_top_unique = {}\n",
760 | "\n",
761 | "from math import exp\n",
762 | "import json\n",
763 | "class ScoreManager:\n",
764 | " def __init__(self, filename=\"output.txt\"):\n",
765 | " self.filename = filename\n",
766 | "\n",
767 | " def write(self, unique_to_score):\n",
768 | " with open(self.filename, 'w', encoding='utf-8') as f:\n",
769 | " for unique, score in unique_to_score.items():\n",
770 | " json_line = json.dumps({unique: score}, ensure_ascii=False)\n",
771 | " f.write(json_line + \"\\n\")\n",
772 | "\n",
773 | " def continue_write(self, unique_to_score, update_key_list):\n",
774 | " with open(self.filename, 'a', encoding='utf-8') as f:\n",
775 | " for key in update_key_list:\n",
776 | " if key in unique_to_score:\n",
777 | " json_line = json.dumps({key: unique_to_score[key]}, ensure_ascii=False)\n",
778 | " f.write(json_line + \"\\n\")\n",
779 | "\n",
780 | " def read(self):\n",
781 | " merged_scores = {}\n",
782 | " with open(self.filename, 'r', encoding='utf-8') as f:\n",
783 | " for line in f:\n",
784 | " score_data = json.loads(line.strip())\n",
785 | " merged_scores.update(score_data)\n",
786 | " return merged_scores\n",
787 | "\n",
788 | "score_manager = ScoreManager(\"./score.jsonl\")\n",
789 | "\n",
790 | "elo_start = 1200\n",
791 | "elo_K = 15\n",
792 | "\n",
793 | "if os.path.exists(\"./score.jsonl\"):\n",
794 | " unique_to_score = score_manager.read()\n",
795 | " for k, v in unique_to_score.items():\n",
796 | " name = k.split(\"_\")[0]\n",
797 | " if name not in name_to_top_unique:\n",
798 | " name_to_top_unique[name] = k\n",
799 | " else:\n",
800 | " if unique_to_score[name_to_top_unique[name]] < v:\n",
801 | " name_to_top_unique[name] = k\n",
802 | "else:\n",
803 | " for data in fighter_data:\n",
804 | " unique_name = get_unique_from_data(data)\n",
805 | " score = elo_start\n",
806 | " unique_to_score[unique_name] = elo_start\n",
807 | " name = data[\"name\"]\n",
808 | " name_to_top_unique[name] = unique_name\n",
809 | " score_manager.write(unique_to_score)\n",
810 | "\n",
811 | "\n",
812 | "\n",
813 | "def get_rank_str(top_n=20):\n",
814 | " global unique_to_score\n",
815 | " global name_to_top_unique\n",
816 | "\n",
817 | " score_name_pair = []\n",
818 | " for name in name_to_top_unique:\n",
819 | " unique = name_to_top_unique[name]\n",
820 | " score = unique_to_score[unique]\n",
821 | " score_name_pair.append((unique, score))\n",
822 | "\n",
823 | " top_n = min(top_n, len(name_to_top_unique))\n",
824 | " score_name_pair.sort(key=lambda x: x[1], reverse=True)\n",
825 | " ans = \"\"\n",
826 | " for i in range(top_n):\n",
827 | " name = score_name_pair[i][0].split(\"_\")[0]\n",
828 | " ans += f\"第{i + 1}名\" + name + \" - \" + str(round(score_name_pair[i][1])) + \" | \"\n",
829 | " return ans\n",
830 | "\n",
831 | "\n",
832 | "\n",
833 | "def update_elo(winner_unique, loser_unique):\n",
834 | " print(winner_unique + \" wins \" + loser_unique)\n",
835 | " update_winner = True\n",
836 | " update_loser = True\n",
837 | "\n",
838 | " global unique_to_score\n",
839 | " global name_to_top_unique\n",
840 | "\n",
841 | " if winner_unique not in unique_to_score:\n",
842 | " unique_to_score[winner_unique] = elo_start\n",
843 | " update_loser = False\n",
844 | "\n",
845 | " if loser_unique not in unique_to_score:\n",
846 | " unique_to_score[loser_unique] = elo_start\n",
847 | "\n",
848 | " Ra = unique_to_score[winner_unique]\n",
849 | " Rb = unique_to_score[loser_unique]\n",
850 | "\n",
851 | " Ea = 1 / (1 + exp((Rb - Ra) / 400))\n",
852 | " Eb = 1 / (1 + exp((Ra - Rb) / 400))\n",
853 | " Sa = 1\n",
854 | " Sb = 0\n",
855 | " unique_to_score[winner_unique] = Ra + elo_K * (Sa - Ea)\n",
856 | " unique_to_score[loser_unique] = Rb + elo_K * (Sb - Eb)\n",
857 | "\n",
858 | " winner_name = winner_unique.split(\"_\")[0]\n",
859 | " loser_name = loser_unique.split(\"_\")[0]\n",
860 | "\n",
861 | " if winner_name not in name_to_top_unique:\n",
862 | " name_to_top_unique[winner_name] = winner_unique\n",
863 | "\n",
864 | " if loser_unique not in name_to_top_unique:\n",
865 | " name_to_top_unique[loser_name] = loser_unique\n",
866 | "\n",
867 | " winner_unique_on_rank = name_to_top_unique[winner_name]\n",
868 | " if unique_to_score[winner_unique] > unique_to_score[winner_unique_on_rank]:\n",
869 | " name_to_top_unique[winner_name] = winner_unique\n",
870 | "\n",
871 | " score_manager.continue_write(unique_to_score, [winner_unique, loser_unique])\n",
872 | "\n",
873 | "\n",
874 | "def get_random_fighter():\n",
875 | " global fighter_data\n",
876 | " return random.choice(fighter_data)\n",
877 | "\n",
878 | "\n",
879 | "def searching_fighter(name):\n",
880 | " global fighter_data\n",
881 | " for data in fighter_data:\n",
882 | " if data[\"name\"] == name:\n",
883 | " return data\n",
884 | " return get_random_fighter()\n",
885 | "\n",
886 | "\n",
887 | "def add_fighter(attr_json_str, skill_jsonl):\n",
888 | " attr_json = json.loads(attr_json_str)\n",
889 | " if \"skills\" in attr_json:\n",
890 | " del attr_json[\"skills\"]\n",
891 | " if \"hp\" in attr_json:\n",
892 | " del attr_json[\"hp\"]\n",
893 | "\n",
894 | " new_attr_json_str = json.dumps(attr_json, ensure_ascii=False)\n",
895 | "\n",
896 | " global fighter_data\n",
897 | " name = attr_json[\"name\"]\n",
898 | "\n",
899 | " data = {\n",
900 | " \"name\": name,\n",
901 | " \"attr_str\": new_attr_json_str,\n",
902 | " \"skills\": skill_jsonl\n",
903 | " }\n",
904 | " fighter_data.append(data)\n",
905 | " print(json.dumps(data, ensure_ascii=False))\n",
906 | " with open(fighter_save_name, 'a', encoding=\"utf-8\") as f:\n",
907 | " f.write(json.dumps(data, ensure_ascii=False) + \"\\n\")\n",
908 | "\n",
909 | "\n",
910 | "def searching_fighter_on_elo(name):\n",
911 | " global fighter_data\n",
912 | " global name_to_top_unique\n",
913 | "\n",
914 | " if name in name_to_top_unique:\n",
915 | " top_unique = name_to_top_unique[name]\n",
916 | " for data in fighter_data:\n",
917 | " if get_unique_from_data(data) == top_unique:\n",
918 | " return data\n",
919 | " return searching_fighter(name)\n",
920 | " else:\n",
921 | " return searching_fighter(name)\n",
922 | "\n",
923 | "\n",
924 | "import gradio as gr\n",
925 | "\n",
926 | "\n",
927 | "def get_attr_str_short(attr_json):\n",
928 | " if \"hp\" in attr_json:\n",
929 | " ans = \"血量:\" + str(attr_json[\"hp\"]) + \"\\n\"\n",
930 | " else:\n",
931 | " ans = \"\"\n",
932 | " ans += \"力量:\" + str(attr_json[\"STR\"]) + \"\\n体质:\" + str(attr_json[\"VIT\"]) + \"\\n速度:\" + str(attr_json[\"SPD\"])\n",
933 | " return ans\n",
934 | "\n",
935 | "\n",
936 | "def get_skill_str_short(attr_json):\n",
937 | " ans = attr_json[\"major_martial_art\"] + \":\\n\"\n",
938 | " for skill in attr_json[\"major_movements\"]:\n",
939 | " ans += skill + \"-\"\n",
940 | " ans += \"\\n\" + attr_json[\"secondary_martial_art\"] + \":\\n\"\n",
941 | " for skill in attr_json[\"secondary_movements\"]:\n",
942 | " ans += skill + \"-\"\n",
943 | " ans += \"\\n 防御:\" + attr_json[\"footwork_and_body_method\"]\n",
944 | " return ans\n",
945 | "\n",
946 | "\n",
947 | "def generate_ma(name, desc, display_board):\n",
948 | " if name.strip() == \"\":\n",
949 | " return \"\", \"\", \"\", \"\", display_board, \"角色名不能为空,输入角色名后生成功法或者创建角色\"\n",
950 | "\n",
951 | " status = \"请为角色进一步生成详细功法\"\n",
952 | "\n",
953 | " role_detail = ma_foo_answer\n",
954 | "\n",
955 | " if name == \"李鲁鲁\":\n",
956 | " json_answer = json.loads(attr_lilulu)\n",
957 | " elif name == \"冷子昂\":\n",
958 | " json_answer = json.loads(attr_lengziang)\n",
959 | " else:\n",
960 | " role_detail = generate_detailed_description(name, desc)\n",
961 | " json_str = generate_attr_json(name, desc, role_detail)\n",
962 | " json_answer = robust_parsing(json_str)\n",
963 | "\n",
964 | " json_answer_str = json.dumps(json_answer, ensure_ascii=False)\n",
965 | "\n",
966 | " skill_desc = get_skill_str_short(json_answer)\n",
967 | "\n",
968 | " display_board.append((\"生成人物\" + json_answer[\"name\"] + \"\\n\" + skill_desc, None))\n",
969 | "\n",
970 | " return role_detail, json_answer_str, get_attr_str_short(json_answer), skill_desc, display_board, status\n",
971 | "\n",
972 | "\n",
973 | "def generate_madetail(player_attribute, display_board):\n",
974 | " if player_attribute.strip() == \"\":\n",
975 | " return \"\", display_board, \"需要生成武功名称,再生成描述。或者直接随机召唤角色\"\n",
976 | "\n",
977 | " status = \"确认两个角色都生成之后,可以进入战斗\"\n",
978 | "\n",
979 | " json_answer = json.loads(player_attribute)\n",
980 | "\n",
981 | " generate_flag = False\n",
982 | "\n",
983 | " ans = skill_foo_desc\n",
984 | " if json_answer[\"name\"] == \"李鲁鲁\":\n",
985 | " ans = skill_lilulu\n",
986 | " elif json_answer[\"name\"] == \"冷子昂\":\n",
987 | " ans = skill_lengziang\n",
988 | " else:\n",
989 | " ans = generate_skill_jsonl(json_answer)\n",
990 | " generate_flag = True\n",
991 | "\n",
992 | " display_board.append((\"为\" + json_answer[\"name\"] + \"生成详细的功法描述\\n\", None))\n",
993 | "\n",
994 | " if generate_flag:\n",
995 | " player = Player(json_answer, ans)\n",
996 | " unique_name = get_unique_from_json(json_answer[\"name\"], json_answer)\n",
997 | " if len(player.skills) > 1 and unique_name != None:\n",
998 | " add_fighter(player_attribute, ans)\n",
999 | " display_board.append((\"将新角色\" + json_answer[\"name\"] + \"录入到数据库\\n\", None))\n",
1000 | "\n",
1001 | " return ans, display_board, status, json_answer[\"name\"]\n",
1002 | "\n",
1003 | "\n",
1004 | "def continue_fight(detailed_attr_player1, detailed_attr_player2, detailed_skill_player1, detailed_skill_player2,\n",
1005 | " display_board, flag_run):\n",
1006 | " print(flag_run)\n",
1007 | " if detailed_attr_player1.strip() == \"\" or detailed_attr_player2.strip() == \"\" or detailed_skill_player1.strip() == \"\" or detailed_skill_player2.strip() == \"\":\n",
1008 | " str1 = \"\"\n",
1009 | " if detailed_attr_player1.strip() != \"\":\n",
1010 | " str1 = get_attr_str_short(json.loads(detailed_attr_player1))\n",
1011 | " str2 = \"\"\n",
1012 | " if detailed_attr_player2.strip() != \"\":\n",
1013 | " str2 = get_attr_str_short(json.loads(detailed_attr_player2))\n",
1014 | " return detailed_attr_player1, detailed_attr_player2, display_board, str1, str2, \"请重新检查人物的生成情况\", flag_run\n",
1015 | "\n",
1016 | " json1 = json.loads(detailed_attr_player1)\n",
1017 | " json2 = json.loads(detailed_attr_player2)\n",
1018 | " name1 = json1[\"name\"]\n",
1019 | " name2 = json2[\"name\"]\n",
1020 | "\n",
1021 | " status = f\"\"\"{name1} 大战 {name2}\"\"\"\n",
1022 | "\n",
1023 | " if \"hp\" in json1 and \"hp\" in json2:\n",
1024 | " if (json1[\"hp\"] <= 0 and json1[\"hp\"] < json2[\"hp\"])or flag_run == \"0\":\n",
1025 | " unique1 = get_unique_from_json(name1, json1)\n",
1026 | " unique2 = get_unique_from_json(name2, json2)\n",
1027 | " flag_run = \"0\"\n",
1028 | " return detailed_attr_player1, detailed_attr_player2, display_board, \"\", \"\", \"战斗结束!请清除战斗或者重新生成人物\", flag_run\n",
1029 | "\n",
1030 | " if (json2[\"hp\"] <= 0 and json2[\"hp\"] < json1[\"hp\"])or flag_run == \"0\":\n",
1031 | " unique1 = get_unique_from_json(name1, json1)\n",
1032 | " unique2 = get_unique_from_json(name2, json2)\n",
1033 | " flag_run = \"0\"\n",
1034 | " return detailed_attr_player1, detailed_attr_player2, display_board, \"\", \"\", \"战斗结束!请清除战斗或者重新生成人物\", flag_run\n",
1035 | "\n",
1036 | " game_manager = GameManager(json1, json2, detailed_skill_player1, detailed_skill_player2)\n",
1037 | " msgs, new_player1, new_player2 = game_manager.run()\n",
1038 | " for msg in msgs:\n",
1039 | " display_board.append(msg)\n",
1040 | "\n",
1041 | " if game_manager.flag == \"player1_win\":\n",
1042 | " unique1 = get_unique_from_json(name1, json1)\n",
1043 | " unique2 = get_unique_from_json(name2, json2)\n",
1044 | " update_elo(unique1, unique2)\n",
1045 | " elif game_manager.flag == \"player2_win\":\n",
1046 | " unique1 = get_unique_from_json(name1, json1)\n",
1047 | " unique2 = get_unique_from_json(name2, json2)\n",
1048 | " update_elo(unique2, unique1)\n",
1049 | "\n",
1050 | " new_player1_str = json.dumps(new_player1, ensure_ascii=False)\n",
1051 | " new_player2_str = json.dumps(new_player2, ensure_ascii=False)\n",
1052 | "\n",
1053 | " return new_player1_str, new_player2_str, display_board, get_attr_str_short(new_player1), get_attr_str_short(\n",
1054 | " new_player2), status, flag_run\n",
1055 | "\n",
1056 | "\n",
1057 | "def callback_random_role(display_board, name_except):\n",
1058 | " data = get_random_fighter()\n",
1059 | " while data[\"name\"] == name_except:\n",
1060 | " data = get_random_fighter()\n",
1061 | " name = data[\"name\"]\n",
1062 | " json_str = data[\"attr_str\"]\n",
1063 | " skills_jsonl = data[\"skills\"]\n",
1064 | " json_answer = json.loads(json_str)\n",
1065 | " display_board.append((\"从数据库选择角色\" + name, None))\n",
1066 | " return name, json_str, skills_jsonl, get_attr_str_short(json_answer), get_skill_str_short(\n",
1067 | " json_answer), display_board, \"1\"\n",
1068 | "\n",
1069 | "\n",
1070 | "def callback_role_from_name(display_board, name):\n",
1071 | " data = searching_fighter_on_elo(name)\n",
1072 | " json_str = data[\"attr_str\"]\n",
1073 | " skills_jsonl = data[\"skills\"]\n",
1074 | " json_answer = json.loads(json_str)\n",
1075 | " display_board.append((\"从数据库选择角色\" + name, None))\n",
1076 | " return name, json_str, skills_jsonl, get_attr_str_short(json_answer), get_skill_str_short(\n",
1077 | " json_answer), display_board\n",
1078 | "\n",
1079 | "\n",
1080 | "def callback_clean_fight(display_board, detailed_attr_player1, detailed_attr_player2):\n",
1081 | " display_board = []\n",
1082 | " json1 = json.loads(detailed_attr_player1)\n",
1083 | " json2 = json.loads(detailed_attr_player2)\n",
1084 | " if \"hp\" in json1:\n",
1085 | " del json1[\"hp\"]\n",
1086 | " if \"hp\" in json2:\n",
1087 | " del json2[\"hp\"]\n",
1088 | "\n",
1089 | " new_detailed_attr_player1 = json.dumps(json1, ensure_ascii=False)\n",
1090 | " new_detailed_attr_player2 = json.dumps(json2, ensure_ascii=False)\n",
1091 | "\n",
1092 | " return display_board, new_detailed_attr_player1, new_detailed_attr_player2\n",
1093 | "\n",
1094 | "\n",
1095 | "def callback_refresh_rank():\n",
1096 | " return get_rank_str()\n",
1097 | "\n",
1098 | "\n",
1099 | "with gr.Blocks() as demo:\n",
1100 | " gr.Markdown(\n",
1101 | " \"\"\"\n",
1102 | " # LuotuoFighter\n",
1103 | "\n",
1104 | " ## 骆驼大乱斗\n",
1105 | "\n",
1106 | " Implemented by 李鲁鲁\n",
1107 | "\n",
1108 | " 项目链接 https://github.com/LC1332/Chat-Haruhi-Suzumiya\n",
1109 | "\n",
1110 | " 这个原型是为了百川Hackathon而初步建立\n",
1111 | "\n",
1112 | " 三种角色建立方式: 根据姓名召唤、随机召唤,或者输入姓名和描述后生成新的人物\n",
1113 | " 姓名召唤会召唤同名人物中战力最强的那个\n",
1114 | " 由于Gradio特性,建立角色要花个几十秒,先点击生成功法,再点击生成功法描述\n",
1115 | " \"\"\"\n",
1116 | " )\n",
1117 | "\n",
1118 | " with gr.Tab(\"战斗\"):\n",
1119 | " with gr.Row():\n",
1120 | " with gr.Column():\n",
1121 | " current_status_p2 = gr.Textbox(label = \"当前状态\", value=\"请输入角色姓名进行召唤\")\n",
1122 | "\n",
1123 | " display_board_p2 = gr.Chatbot(height = 800)\n",
1124 | "\n",
1125 | " submit_fight2_p2 = gr.Button(\"继续战斗!\")\n",
1126 | " clean_fight_p2 = gr.Button(\"清空战斗\")\n",
1127 | "\n",
1128 | " with gr.Column():\n",
1129 | "\n",
1130 | " with gr.Row():\n",
1131 | " name_player1_p2 = gr.Textbox(label=\"角色1姓名\", scale=1, interactive = True, value = \"李鲁鲁\")\n",
1132 | "\n",
1133 | " with gr.Row():\n",
1134 | " random_sel_player1_p2 = gr.Button(\"随机召唤\")\n",
1135 | " call_player1_with_name1_p2 = gr.Button(\"根据姓名召唤\")\n",
1136 | "\n",
1137 | "\n",
1138 | " with gr.Row():\n",
1139 | " name_player2_p2 = gr.Textbox(label=\"角色2姓名\", scale=1, interactive = False, value = \"冷子昂\")\n",
1140 | "\n",
1141 | " with gr.Row():\n",
1142 | " random_sel_player2_p2 = gr.Button(\"随机召唤2\")\n",
1143 | "\n",
1144 | "\n",
1145 | " with gr.Row():\n",
1146 | " submit_fight_p2 = gr.Button(\"继续战斗!\")\n",
1147 | "\n",
1148 | " with gr.Row():\n",
1149 | " attr_player1_p2 = gr.TextArea(label = \"角色1属性\")\n",
1150 | " skill_player1_p2 = gr.TextArea(label = \"角色1功法描述\", visible = False)\n",
1151 | "\n",
1152 | " with gr.Row():\n",
1153 | " attr_player2_p2 = gr.TextArea(label = \"角色2属性\")\n",
1154 | " skill_player2_p2 = gr.TextArea(label = \"角色2功法描述\", visible = False)\n",
1155 | "\n",
1156 | " with gr.Row():\n",
1157 | "\n",
1158 | " with gr.Column():\n",
1159 | " detailed_description_player1_p2 = gr.TextArea(label = \"角色1具体描述\", visible = False)\n",
1160 | " detailed_skill_player1_p2 = gr.TextArea(label = \"角色1技能json\", visible = False)\n",
1161 | " detailed_attr_player1_p2 = gr.TextArea(label = \"角色1属性json\", visible = False)\n",
1162 | "\n",
1163 | " with gr.Column():\n",
1164 | " detailed_description_player2_p2 = gr.TextArea(label = \"角色2具体描述\", visible = False)\n",
1165 | " detailed_skill_player2_p2 = gr.TextArea(label = \"角色2技能json\", visible = False)\n",
1166 | " detailed_attr_player2_p2 = gr.TextArea(label = \"角色2属性json\", visible = False)\n",
1167 | " flag_run = gr.Textbox(label = \"是否可以运行\", value = \"1\", visible = False)\n",
1168 | " with gr.Tab(\"创建\"):\n",
1169 | " with gr.Column():\n",
1170 | "\n",
1171 | " current_status_p1 = gr.Textbox(label = \"当前状态\", value=\"请输入角色姓名生成功法\")\n",
1172 | " with gr.Row():\n",
1173 | " name_player1_p1 = gr.Textbox(label=\"角色姓名\", scale=1, interactive = True, value = \"李鲁鲁\")\n",
1174 | " desc_player1_p1 = gr.Textbox(label=\"角色描述\", scale=20, value = \"师从,主修剑法\", interactive = True)\n",
1175 | " # with gr.Row():\n",
1176 | " gr.\n",
1177 | " generate_ma_player1_p1 = gr.Button(\"生成功法\")\n",
1178 | " with gr.Row():\n",
1179 | " attr_player1_p1 = gr.TextArea(label = \"角色属性\")\n",
1180 | " skill_player1_p1 = gr.TextArea(label = \"角色功法描述\")\n",
1181 | " generate_madetail_player1_p1 = gr.Button(\"生成功法描述\")\n",
1182 | " with gr.Row():\n",
1183 | " detailed_description_player1_p1 = gr.TextArea(label = \"角色具体描述\")\n",
1184 | " detailed_skill_player1_p1 = gr.TextArea(label = \"角色技能json\")\n",
1185 | " detailed_attr_player1_p1 = gr.TextArea(label = \"角色属性json\")\n",
1186 | " display_board_p1 = gr.Chatbot(height = 100, visible = False)\n",
1187 | "\n",
1188 | " with gr.Tab(\"对战天梯\"):\n",
1189 | " with gr.Column():\n",
1190 | " rank_showboard_p3 = gr.TextArea(label = \"天梯\")\n",
1191 | " refresh_rank_p3 = gr.Button(\"刷新天梯\")\n",
1192 | "\n",
1193 | "\n",
1194 | " with gr.Tab(\"原先的界面\"):\n",
1195 | "\n",
1196 | " with gr.Row():\n",
1197 | " with gr.Column():\n",
1198 | " current_status = gr.Textbox(label = \"当前状态\", value=\"请输入角色姓名进行召唤\")\n",
1199 | "\n",
1200 | " display_board = gr.Chatbot(height = 800)\n",
1201 | "\n",
1202 | " submit_fight2 = gr.Button(\"继续战斗!\")\n",
1203 | " clean_fight = gr.Button(\"清空战斗\")\n",
1204 | "\n",
1205 | "\n",
1206 | " with gr.Column():\n",
1207 | "\n",
1208 | " with gr.Row():\n",
1209 | " name_player1 = gr.Textbox(label=\"角色1姓名\", scale=1, interactive = True, value = \"李鲁鲁\")\n",
1210 | " desc_player1 = gr.Textbox(label=\"角色1描述\", scale=20, value = \"师从,主修剑法\", interactive = True)\n",
1211 | "\n",
1212 | " with gr.Row():\n",
1213 | " generate_ma_player1 = gr.Button(\"生成功法\")\n",
1214 | " generate_madetail_player1 = gr.Button(\"生成功法描述\")\n",
1215 | "\n",
1216 | " with gr.Row():\n",
1217 | " random_sel_player1 = gr.Button(\"随机召唤\")\n",
1218 | " call_player1_with_name1 = gr.Button(\"根据姓名召唤\")\n",
1219 | "\n",
1220 | "\n",
1221 | " with gr.Row():\n",
1222 | " name_player2 = gr.Textbox(label=\"角色2姓名\", scale=1, interactive = True, value = \"冷子昂\")\n",
1223 | " desc_player2 = gr.Textbox(label=\"角色2描述\", scale=20, value = \"师从,主修剑法\", interactive = True)\n",
1224 | " with gr.Row():\n",
1225 | " generate_ma_player2 = gr.Button(\"生成功法\")\n",
1226 | " generate_madetail_player2 = gr.Button(\"生成功法描述\")\n",
1227 | "\n",
1228 | " with gr.Row():\n",
1229 | " random_sel_player2 = gr.Button(\"随机召唤2\")\n",
1230 | " call_player1_with_name2 = gr.Button(\"根据姓名召唤2\")\n",
1231 | "\n",
1232 | " with gr.Row():\n",
1233 | " submit_fight = gr.Button(\"继续战斗!\")\n",
1234 | "\n",
1235 | " with gr.Row():\n",
1236 | " attr_player1 = gr.TextArea(label = \"角色1属性\")\n",
1237 | " skill_player1 = gr.TextArea(label = \"角色1功法描述\")\n",
1238 | "\n",
1239 | " with gr.Row():\n",
1240 | " attr_player2 = gr.TextArea(label = \"角色2属性\")\n",
1241 | " skill_player2 = gr.TextArea(label = \"角色2功法描述\")\n",
1242 | "\n",
1243 | " with gr.Row():\n",
1244 | " refresh_rank = gr.Button(\"刷新天梯\")\n",
1245 | "\n",
1246 | " with gr.Row():\n",
1247 | " rank_showboard = gr.TextArea(label = \"天梯\")\n",
1248 | "\n",
1249 | " with gr.Row():\n",
1250 | " with gr.Column():\n",
1251 | " detailed_description_player1 = gr.TextArea(label = \"角色1具体描述\")\n",
1252 | " detailed_skill_player1 = gr.TextArea(label = \"角色1技能json\")\n",
1253 | " detailed_attr_player1 = gr.TextArea(label = \"角色1属性json\")\n",
1254 | "\n",
1255 | " with gr.Column():\n",
1256 | " detailed_description_player2 = gr.TextArea(label = \"角色2具体描述\")\n",
1257 | " detailed_skill_player2 = gr.TextArea(label = \"角色2技能json\")\n",
1258 | " detailed_attr_player2 = gr.TextArea(label = \"角色2属性json\")\n",
1259 | "\n",
1260 | " random_sel_player1_p2.click( fn = callback_random_role, inputs = [display_board_p2, name_player1_p2], outputs = [name_player1_p2, detailed_attr_player1_p2, detailed_skill_player1_p2, attr_player1_p2, skill_player1_p2, display_board_p2, flag_run])\n",
1261 | " random_sel_player2_p2.click( fn = callback_random_role, inputs = [display_board_p2, name_player1_p2], outputs = [name_player2_p2, detailed_attr_player2_p2, detailed_skill_player2_p2, attr_player2_p2, skill_player2_p2, display_board_p2, flag_run])\n",
1262 | "\n",
1263 | " call_player1_with_name1_p2.click( fn = callback_role_from_name, inputs = [display_board_p2,name_player1_p2], outputs = [name_player1_p2, detailed_attr_player1_p2, detailed_skill_player1_p2, attr_player1_p2, skill_player1_p2, display_board_p2])\n",
1264 | "\n",
1265 | " clean_fight_p2.click( fn = callback_clean_fight, inputs = [display_board_p2,detailed_attr_player1_p2,detailed_attr_player2_p2], \\\n",
1266 | " outputs = [display_board_p2,detailed_attr_player1_p2,detailed_attr_player2_p2])\n",
1267 | "\n",
1268 | " # callback_role_from_name\n",
1269 | "\n",
1270 | " submit_fight_p2.click( fn = continue_fight, \\\n",
1271 | " inputs = [detailed_attr_player1_p2,detailed_attr_player2_p2, detailed_skill_player1_p2,detailed_skill_player2_p2, display_board_p2, flag_run],\\\n",
1272 | " outputs = [detailed_attr_player1_p2,detailed_attr_player2_p2, display_board_p2,attr_player1_p2,attr_player2_p2, current_status_p2, flag_run])\n",
1273 | "\n",
1274 | " submit_fight2_p2.click( fn = continue_fight, \\\n",
1275 | " inputs = [detailed_attr_player1_p2,detailed_attr_player2_p2, detailed_skill_player1_p2,detailed_skill_player2_p2, display_board_p2, flag_run],\\\n",
1276 | " outputs = [detailed_attr_player1_p2,detailed_attr_player2_p2, display_board_p2,attr_player1_p2,attr_player2_p2, current_status_p2, flag_run])\n",
1277 | " generate_ma_player1_p1.click( fn = generate_ma, inputs = [name_player1_p1, desc_player1_p1,display_board_p1], outputs = [detailed_description_player1_p1,detailed_attr_player1_p1,attr_player1_p1,skill_player1_p1,display_board_p1,current_status_p1])\n",
1278 | " # generate_ma_player2.click( fn = generate_ma, inputs = [name_player2, desc_player2,display_board], outputs = [detailed_description_player2,detailed_attr_player2,attr_player2,skill_player2,display_board,current_status])\n",
1279 | " generate_madetail_player1_p1.click( fn = generate_madetail, inputs = [detailed_attr_player1_p1,display_board_p1], outputs = [detailed_skill_player1_p1,display_board_p1,current_status_p1,name_player1_p2])\n",
1280 | " # generate_madetail_player2.click( fn = generate_madetail, inputs = [detailed_attr_player2,display_board], outputs = [detailed_skill_player2,display_board,current_status])\n",
1281 | "\n",
1282 | " generate_ma_player1.click( fn = generate_ma, inputs = [name_player1, desc_player1,display_board], outputs = [detailed_description_player1,detailed_attr_player1,attr_player1,skill_player1,display_board,current_status])\n",
1283 | " generate_ma_player2.click( fn = generate_ma, inputs = [name_player2, desc_player2,display_board], outputs = [detailed_description_player2,detailed_attr_player2,attr_player2,skill_player2,display_board,current_status])\n",
1284 | " generate_madetail_player1.click( fn = generate_madetail, inputs = [detailed_attr_player1,display_board], outputs = [detailed_skill_player1,display_board,current_status,name_player1])\n",
1285 | " generate_madetail_player2.click( fn = generate_madetail, inputs = [detailed_attr_player2,display_board], outputs = [detailed_skill_player2,display_board,current_status,name_player2])\n",
1286 | "\n",
1287 | " random_sel_player1.click( fn = callback_random_role, inputs = [display_board, name_player2], outputs = [name_player1, detailed_attr_player1, detailed_skill_player1, attr_player1, skill_player1, display_board, flag_run])\n",
1288 | " random_sel_player2.click( fn = callback_random_role, inputs = [display_board, name_player1], outputs = [name_player2, detailed_attr_player2, detailed_skill_player2, attr_player2, skill_player2, display_board, flag_run])\n",
1289 | "\n",
1290 | " call_player1_with_name1.click( fn = callback_role_from_name, inputs = [display_board,name_player1], outputs = [name_player1, detailed_attr_player1, detailed_skill_player1, attr_player1, skill_player1, display_board])\n",
1291 | " call_player1_with_name2.click( fn = callback_role_from_name, inputs = [display_board,name_player2], outputs = [name_player2, detailed_attr_player2, detailed_skill_player2, attr_player2, skill_player2, display_board])\n",
1292 | "\n",
1293 | " refresh_rank.click( fn = callback_refresh_rank, inputs = [], outputs = [rank_showboard])\n",
1294 | " refresh_rank_p3.click( fn = callback_refresh_rank, inputs = [], outputs = [rank_showboard_p3])\n",
1295 | "\n",
1296 | " clean_fight.click( fn = callback_clean_fight, inputs = [display_board,detailed_attr_player1,detailed_attr_player2], \\\n",
1297 | " outputs = [display_board,detailed_attr_player1,detailed_attr_player2])\n",
1298 | "\n",
1299 | " # callback_role_from_name\n",
1300 | "\n",
1301 | " submit_fight.click( fn = continue_fight, \\\n",
1302 | " inputs = [detailed_attr_player1,detailed_attr_player2, detailed_skill_player1,detailed_skill_player2, display_board, flag_run],\\\n",
1303 | " outputs = [detailed_attr_player1,detailed_attr_player2, display_board,attr_player1,attr_player2, current_status])\n",
1304 | "\n",
1305 | " submit_fight2.click( fn = continue_fight, \\\n",
1306 | " inputs = [detailed_attr_player1,detailed_attr_player2, detailed_skill_player1,detailed_skill_player2, display_board, flag_run],\\\n",
1307 | " outputs = [detailed_attr_player1,detailed_attr_player2, display_board,attr_player1,attr_player2, current_status])\n",
1308 | "\n",
1309 | "# demo.launch(debug=False, share = True)\n",
1310 | "demo.launch(debug=True, share = True, server_name=\"0.0.0.0\")\n"
1311 | ]
1312 | }
1313 | ]
1314 | }
--------------------------------------------------------------------------------
/demo_code/node_data_2.txt:
--------------------------------------------------------------------------------
1 | 序号|事件名|敌人战斗力|奖励|描述
2 | -|-|-|-|-
3 | 1|踏上英灵殿|0|-|你来到英灵殿,开始了成为英雄的旅程
4 | 2|北方食人妖|15|str+1|北方食人妖芬尼尔持有神秘战斧,如果打败它,你的力量将得到提升
5 | 3|挑战巨龙法夫纳|20|str+3|恶龙法夫纳拥有无穷力量,如果你能打败它,你的力量将大幅提升
6 | 4|冰原巨人|16|-|冰原巨人体型巨大,这场战斗对你很艰难
7 | 5|黑暗精灵|17|spd+1|黑暗精灵速度极快,击败它可以提高你的敏捷
8 | 6|海姆冥界使者|21|spd+3|海姆冥界使者将考验你的反应能力,如果成功击败,你的敏捷将大幅提升
9 | 7|山地巨人|18|-|山地巨人力大无穷,这场战斗消耗你大量体力
10 | 8|北地冰原巨熊|19|vit+1|北地冰原巨熊体质惊人,打败它可以增强你的生命力
11 | 9|神圣武士泰尔|21|vit+3|神圣武士泰尔拥有神力,如果你能战胜他,你的生命力将大幅提升
12 | 10|最后的试炼|25|-|这是成为英雄的最后试炼,只有打败25战力的对手才能通过
--------------------------------------------------------------------------------
/demo_code/print_DND_fighter_baichuan.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {
6 | "id": "view-in-github"
7 | },
8 | "source": [
9 | "
"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": 2,
15 | "metadata": {
16 | "id": "rA9kiMWgT8jP"
17 | },
18 | "outputs": [],
19 | "source": [
20 | "!pip -q install gradio langchain tiktoken openai"
21 | ]
22 | },
23 | {
24 | "cell_type": "markdown",
25 | "metadata": {
26 | "id": "0sorN_EgWgv4"
27 | },
28 | "source": [
29 | "- [x] 试一下langchain\n",
30 | "- [x] 如果langchain不行,试一下openai默认接口\n",
31 | "- [x] 如果两者有一个可以 完成功法创建逻辑"
32 | ]
33 | },
34 | {
35 | "cell_type": "code",
36 | "execution_count": 3,
37 | "metadata": {
38 | "id": "DdjBBvU0W8f5"
39 | },
40 | "outputs": [],
41 | "source": [
42 | "import os\n",
43 | "\n",
44 | "key = \"sk-w2QMrpcNV2apgyLQ4EeVg\"\n",
45 | "key_bytes = key.encode()\n",
46 | "os.environ[\"OPENAI_API_KEY\"] = key_bytes.decode('utf-8')\n",
47 | "\n"
48 | ]
49 | },
50 | {
51 | "cell_type": "code",
52 | "execution_count": 4,
53 | "metadata": {
54 | "colab": {
55 | "base_uri": "https://localhost:8080/"
56 | },
57 | "id": "PlJVVdzDXBu9",
58 | "outputId": "16d0a5c9-d588-4a3e-c702-1f01ebcffe76"
59 | },
60 | "outputs": [
61 | {
62 | "output_type": "stream",
63 | "name": "stdout",
64 | "text": [
65 | "你好,李鲁鲁!有什么我可以帮助你的吗?\n"
66 | ]
67 | }
68 | ],
69 | "source": [
70 | "from langchain.chat_models import ChatOpenAI\n",
71 | "from langchain.prompts.chat import (\n",
72 | " ChatPromptTemplate,\n",
73 | " SystemMessagePromptTemplate,\n",
74 | " AIMessagePromptTemplate,\n",
75 | " HumanMessagePromptTemplate,\n",
76 | ")\n",
77 | "from langchain.schema import (\n",
78 | " AIMessage,\n",
79 | " HumanMessage,\n",
80 | " SystemMessage\n",
81 | ")\n",
82 | "\n",
83 | "chat = ChatOpenAI(model=\"gpt-3.5-turbo\", temperature = 0.0)\n",
84 | "\n",
85 | "smart_system_prompt = \"\"\"You are ChatGPT, a large language model trained by OpenAI.\n",
86 | "Knowledge cutoff: 2021-09\n",
87 | "Current date: 2023-03-15\"\"\"\n",
88 | "\n",
89 | "messages = [\n",
90 | " SystemMessage(content=smart_system_prompt),\n",
91 | " HumanMessage(content=\"我的名字叫李鲁鲁\"),\n",
92 | "]\n",
93 | "\n",
94 | "response = chat(messages)\n",
95 | "print(response.content)\n",
96 | "\n"
97 | ]
98 | },
99 | {
100 | "cell_type": "code",
101 | "execution_count": 5,
102 | "metadata": {
103 | "id": "mnOOKTCkXIUq"
104 | },
105 | "outputs": [],
106 | "source": [
107 | "def generate_detailed_description( name , description ):\n",
108 | " task_message = f\"\"\"我的名字叫“{name}”,假设我是一个武侠中的游戏角色,{description}\n",
109 | " 请基于我的名字和门派,先为我设计2套武功和一套身法或者招架。\n",
110 | "\n",
111 | " 再为每套武功设计4个对应招式的名字。\"\"\"\n",
112 | "\n",
113 | " messages = [\n",
114 | " SystemMessage(content=smart_system_prompt),\n",
115 | " HumanMessage(content=task_message),\n",
116 | " ]\n",
117 | "\n",
118 | " chat = ChatOpenAI(model=\"gpt-3.5-turbo\", temperature = 0.3)\n",
119 | "\n",
120 | " response = chat(messages)\n",
121 | " return response.content\n",
122 | "\n",
123 | "\n",
124 | "\n",
125 | "\n",
126 | "name = \"黄蓉\"\n",
127 | "\n",
128 | "description = \"丐帮帮主黄蓉,擅长打狗棒法和落英神剑掌,身法为逍遥游。\"\n",
129 | "\n",
130 | "# detailed_description = generate_detailed_description( name, description )\n",
131 | "\n",
132 | "# print(detailed_description)\n"
133 | ]
134 | },
135 | {
136 | "cell_type": "code",
137 | "execution_count": 6,
138 | "metadata": {
139 | "id": "WtAnuheRY-kL"
140 | },
141 | "outputs": [],
142 | "source": [
143 | "def generate_attr_json( name, description, detailed_description ):\n",
144 | " task_message = f\"\"\"我正在为我的武侠游戏设计人物。给定一个人物和这个人物的背景描述(可选)\n",
145 | "\n",
146 | "我希望你根据这个人物的背景和名字以及输入的suggestion信息,为我生成这个人的资料,以json的格式输出,包括\n",
147 | "\n",
148 | "description: 这个角色的背景等信息\n",
149 | "weapon: 这个人使用的武器种类,\n",
150 | "major_martial_art: 这个人的主要武学\n",
151 | "major_movements: 这个人主要武学的4个对应招式的名字。招式的名字需要尽可能和major_martial_art有关。movements的名字尽量不要使用重复的文字。可以使用形象的动作或者是一些动物的比喻。\n",
152 | "major_damage: 主武学的威力,50到150之间的整数。重视速度的功法威力会低一些。重视攻击的功法威力会高一些\n",
153 | "secondary_movements: 这个角色的次要武学\n",
154 | "secondary_movements: 这个人次要武学的4个对应招式的名字。招式的名字需要尽可能和secondary_movements有关\n",
155 | "secondary_damage: 次要武学的威力,50到150之间的整数。\n",
156 | "footwork_and_body_method: 这个角色的轻功或者防御功法\n",
157 | "STR: 角色的攻击力, 0-20之间的整数\n",
158 | "VIT: 角色的体质, 0-20之间的整数\n",
159 | "SPD: 角色的速度,0-20之间的整数\n",
160 | "\"\"\"\n",
161 | " example_input = \"\"\"example_input:\n",
162 | "name: 令狐冲\n",
163 | "description: -\n",
164 | "suggestion:-\"\"\"\n",
165 | "\n",
166 | " example_output = \"\"\"example_output:\n",
167 | "{\n",
168 | " \"name\": \"令狐冲\",\n",
169 | " \"description\": \"华山派的大师兄\",\n",
170 | " \"weapon\": \"剑\",\n",
171 | " \"major_martial_art\": \"独孤九剑\",\n",
172 | " \"major_movements\": [\"独孤九剑破剑式\",\"独孤九剑总诀式\",\"独孤九剑破气式\",\"独孤九剑破刀式\"],\n",
173 | " \"major_damage\": 70,\n",
174 | " \"secondary_martial_art\": \"华山剑法\",\n",
175 | " \"secondary_movements\": [\"有凤来仪\",\"飞沙走石\",\"百丈飞瀑\",\"青山隐隐\"],\n",
176 | " \"secondary_damage\":80,\n",
177 | " \"footwork_and_body_method\": \"华山身法\",\n",
178 | " \"STR\":10,\n",
179 | " \"VIT\":3,\n",
180 | " \"SPD\":20\n",
181 | "}\"\"\"\n",
182 | "\n",
183 | " input = f\"\"\"input:\n",
184 | "name: {name},\n",
185 | "description: {description},\n",
186 | "suggestion: `{detailed_description}`\n",
187 | " \"\"\"\n",
188 | "\n",
189 | " messages = [\n",
190 | " SystemMessage(content=smart_system_prompt),\n",
191 | " HumanMessage(content=task_message),\n",
192 | " HumanMessage(content=example_input),\n",
193 | " AIMessage(content=example_output),\n",
194 | " HumanMessage(content=input)]\n",
195 | "\n",
196 | " chat = ChatOpenAI(model=\"gpt-3.5-turbo\", temperature = 0.1)\n",
197 | "\n",
198 | " response = chat(messages)\n",
199 | " return response.content\n",
200 | "\n",
201 | "\n",
202 | "\n",
203 | "name = \"黄蓉\"\n",
204 | "\n",
205 | "description = \"丐帮帮主黄蓉,擅长打狗棒法和落英神剑掌,身法为逍遥游。\"\n",
206 | "\n",
207 | "detailed_description = \"\"\"作为丐帮帮主黄蓉,您擅长打狗棒法和落英神剑掌,身法为逍遥游。以下是为您设计的两套武功和一套身法(招架):\n",
208 | "\n",
209 | "套路一:打狗棒法\n",
210 | "- 武功一:打狗棒法是丐帮的绝技,以棒法为主要攻击手段,威力巨大,灵活多变。\n",
211 | "- 武功二:落英神剑掌是黄蓉自创的剑掌技法,结合了剑法和掌法的特点,攻守兼备。\n",
212 | "- 身法/招架:逍遥游是黄蓉独特的身法,轻盈灵动,能够迅速躲避敌人的攻击。\n",
213 | "\n",
214 | "套路二:落英神剑掌\n",
215 | "- 武功一:落英神剑掌是黄蓉的拿手绝技,以剑掌相结合,攻击迅猛而准确。\n",
216 | "- 武功二:打狗棒法是黄蓉在丐帮学习的棒法,以棒为主要武器,威力强大。\n",
217 | "- 身法/招架:逍遥游是黄蓉的身法,轻灵敏捷,能够迅速躲避敌人的攻击。\n",
218 | "\n",
219 | "以下是每套武功对应的四个招式的名字:\n",
220 | "\n",
221 | "套路一:打狗棒法\n",
222 | "1. 狗啸山林:以棒法挥舞如狗啸声,迅猛有力,攻敌要害。\n",
223 | "2. 棒影重重:以迅猛的棒影覆盖敌人,让对手难以躲避。\n",
224 | "3. 狗尾续貂:以迅捷的棒法攻击对手的下盘,削弱其防守。\n",
225 | "4. 狗急跳墙:以快速的棒法攻势,迫使对手无处可逃。\n",
226 | "\n",
227 | "套路二:落英神剑掌\n",
228 | "1. 落英如雨:以掌法如落英般飘逸,攻敌时如雨点般密集。\n",
229 | "2. 神剑破空:以剑掌相结合,剑气激荡,破空而出,攻敌要害。\n",
230 | "3. 飞花流水:以灵动的剑掌连绵不断,如水中飞舞的花瓣。\n",
231 | "4. 剑指苍穹:以剑掌合一,指向天空,释放出强大的攻击力。\n",
232 | "\n",
233 | "请注意,以上是根据您的名字和门派进行的设计,如有需要,您可以根据角色的特点和背景进行进一步的调整和发挥。\"\"\"\n",
234 | "\n",
235 | "\n",
236 | "# json_str = generate_attr_json( name, description, detailed_description )\n",
237 | "# print(json_str)\n"
238 | ]
239 | },
240 | {
241 | "cell_type": "code",
242 | "execution_count": 7,
243 | "metadata": {
244 | "id": "ny95Yg4xazOE"
245 | },
246 | "outputs": [],
247 | "source": [
248 | "import json\n",
249 | "\n",
250 | "def robust_parsing(input_str):\n",
251 | " try:\n",
252 | " return json.loads(input_str)\n",
253 | " except json.JSONDecodeError:\n",
254 | " start = input_str.find('{')\n",
255 | " end = input_str.rfind('}') + 1\n",
256 | " if start != -1 and end != -1:\n",
257 | " try:\n",
258 | " return json.loads(input_str[start:end])\n",
259 | " except json.JSONDecodeError:\n",
260 | " pass\n",
261 | "\n",
262 | " return None\n",
263 | "\n",
264 | "# print(robust_parsing(json_str))\n",
265 | "\n",
266 | "# print(robust_parsing(\"一二三四像首歌\"+json_str+\"日落西山打靶归来\"))"
267 | ]
268 | },
269 | {
270 | "cell_type": "code",
271 | "execution_count": 8,
272 | "metadata": {
273 | "id": "-x6Ow6AgdGRg"
274 | },
275 | "outputs": [],
276 | "source": [
277 | "def generate_skill_detail(martial_art_name, movements):\n",
278 | " task_message = \"\"\"现在我希望你根据武侠小说中的武功和招式的名字。为招式补全合理的description和missing描述。\n",
279 | "在description的描述中,player可以击中目标,可以有兵器撞击声响等描述。\n",
280 | "在missing描述中,player并不一定击中目标,不可以有击落、击中、夺去这样的描述\n",
281 | "在用[player]代表技能的使用者,用[target]代表技能的目标。结果需用合理的jsonl格式展示,下面是一个例子。\"\"\"\n",
282 | "\n",
283 | " example_input = \"\"\"example input:\n",
284 | "martial_art_name = 华山剑法\n",
285 | "{\"招式\":\"百丈飞瀑\"}\n",
286 | "{\"招式\":\"百鸟朝凤\"}\n",
287 | "{\"招式\":\"青山隐隐\"}\n",
288 | "{\"招式\":\"飞沙走石\"}\"\"\"\n",
289 | "\n",
290 | " example_output = \"\"\"example output:\n",
291 | "{\"招式\":\"百丈飞瀑\",\"description\":\"[player]翻身回剑,剑诀斜引,一招“百丈飞瀑”,剑锋从半空中直泻下来\",\"missing\":\"[player]一咬牙,翻身回剑,剑诀斜引,一招“百丈飞瀑”,剑锋从半空中直泻下来\"}\n",
292 | "{\"招式\":\"百鸟朝凤\",\"description\":\"[player]长剑一起,使一招“百鸟朝凤”,但见剑尖乱颤,霎时间便如化为数十个剑尖,罩住[target]中盘\",\"missing\":\"[player]使一招“百鸟朝凤”,但见剑尖乱颤,霎时间便如化为数十个剑尖,向[target]飞去\"}\n",
293 | "{\"招式\":\"青山隐隐\", \"description\":\"[player]吸一口气,长剑中宫直进,剑尖不住颤动,剑到中途,忽然转而向上,乃是一招“青山隐隐”,端的是若有若无,变幻无方。\",\"missing\":\"[player]吸一口气,长剑中宫直进,剑尖不住颤动,剑到中途,忽然转而向上,乃是一招“青山隐隐”,端的是若有若无,变幻无方。\"}\n",
294 | "{\"招式\":\"飞沙走石\", \"description\":\"长剑挺起,使一招“飞沙走石”,内劲直贯剑尖,寒光点点,挡的一声,击中的[target]胸口。\",\"missing\":\"长剑挺起,使一招“飞沙走石”,内劲直贯剑尖,寒光点点,直向[target]胸口刺去。\"}\"\"\"\n",
295 | "\n",
296 | " input = \"input:\\nmartial_art_name = \" + martial_art_name + \"\\n\"\n",
297 | " for m in movements:\n",
298 | " input += f\"\"\"{{\"招式\":\"{m}\"\\}}\\n\"\"\"\n",
299 | "\n",
300 | " messages = [\n",
301 | " SystemMessage(content=smart_system_prompt),\n",
302 | " HumanMessage(content=task_message),\n",
303 | " HumanMessage(content=example_input),\n",
304 | " AIMessage(content=example_output),\n",
305 | " HumanMessage(content=input)]\n",
306 | "\n",
307 | " chat = ChatOpenAI(model=\"gpt-3.5-turbo\", temperature = 0.1)\n",
308 | "\n",
309 | " response = chat(messages)\n",
310 | " return response.content\n",
311 | "\n",
312 | "json_str_huangrong = \"\"\"{\n",
313 | " \"name\": \"黄蓉\",\n",
314 | " \"description\": \"丐帮帮主黄蓉,擅长打狗棒法和落英神剑掌,身法为逍遥游。\",\n",
315 | " \"weapon\": \"棒、剑\",\n",
316 | " \"major_martial_art\": \"打狗棒法\",\n",
317 | " \"major_movements\": [\"狗啸山林\", \"棒影重重\", \"狗尾续貂\", \"狗急跳墙\"],\n",
318 | " \"major_damage\": 90,\n",
319 | " \"secondary_martial_art\": \"落英神剑掌\",\n",
320 | " \"secondary_movements\": [\"落英如雨\", \"神剑破空\", \"飞花流水\", \"剑指苍穹\"],\n",
321 | " \"secondary_damage\": 80,\n",
322 | " \"footwork_and_body_method\": \"逍遥游\",\n",
323 | " \"STR\": 15,\n",
324 | " \"VIT\": 10,\n",
325 | " \"SPD\": 18\n",
326 | "}\"\"\"\n",
327 | "\n",
328 | "# json_huangrong = robust_parsing(json_str_huangrong)\n",
329 | "\n",
330 | "\n",
331 | "# huanrong_major_skills = generate_skill_detail(json_huangrong[\"major_martial_art\"], json_huangrong[\"major_movements\"])\n",
332 | "\n",
333 | "\n",
334 | "# print(huanrong_major_skills)\n",
335 | "\n"
336 | ]
337 | },
338 | {
339 | "cell_type": "code",
340 | "execution_count": 9,
341 | "metadata": {
342 | "id": "6gTpEYoIe9KQ"
343 | },
344 | "outputs": [],
345 | "source": [
346 | "def generate_skill_jsonl(json_data):\n",
347 | " major_skills = generate_skill_detail(json_data[\"major_martial_art\"], json_data[\"major_movements\"])\n",
348 | " secondary_skills = generate_skill_detail(json_data[\"secondary_martial_art\"], json_data[\"secondary_movements\"])\n",
349 | "\n",
350 | " all_skills = major_skills + \"\\n\" + secondary_skills\n",
351 | "\n",
352 | " ans = \"\"\n",
353 | "\n",
354 | " lines = all_skills.split(\"\\n\")\n",
355 | " for line in lines:\n",
356 | " json_data = robust_parsing(line)\n",
357 | " if json_data is not None:\n",
358 | " json_str = json.dumps(json_data, ensure_ascii=False)\n",
359 | " ans += json_str + \"\\n\"\n",
360 | "\n",
361 | " return ans\n",
362 | "\n",
363 | "\n",
364 | "# skill_huangrong = generate_skill_jsonl(json_huangrong)\n",
365 | "\n",
366 | "# print(skill_huangrong)\n",
367 | "\n"
368 | ]
369 | },
370 | {
371 | "cell_type": "code",
372 | "execution_count": 10,
373 | "metadata": {
374 | "id": "vcSQnTppRItD"
375 | },
376 | "outputs": [],
377 | "source": [
378 | "import random\n",
379 | "\n",
380 | "class Player:\n",
381 | " def __init__(self, attr_json, skill_jsonl):\n",
382 | " self.name = attr_json[\"name\"]\n",
383 | " self.STR = attr_json[\"STR\"]\n",
384 | " self.SPD = attr_json[\"SPD\"]\n",
385 | " self.VIT = attr_json[\"VIT\"]\n",
386 | " if \"major_damage\" in attr_json:\n",
387 | " self.major_damage = attr_json[\"major_damage\"]\n",
388 | " else:\n",
389 | " self.major_damage = 65\n",
390 | "\n",
391 | " if \"secondary_damage\" in attr_json:\n",
392 | " self.secondary_damage = attr_json[\"secondary_damage\"]\n",
393 | " else:\n",
394 | " self.secondary_damage = 50\n",
395 | "\n",
396 | " self.normalize_attr()\n",
397 | " if \"hp\" in attr_json:\n",
398 | " self.hp = attr_json[\"hp\"]\n",
399 | " else:\n",
400 | " self.hp = (self.VIT + 10) * 30\n",
401 | "\n",
402 | " if \"skills\" in attr_json:\n",
403 | " self.skills = attr_json[\"skills\"]\n",
404 | " else:\n",
405 | " self.skills = self.parsing_skill(skill_jsonl)\n",
406 | "\n",
407 | " self.original_json = attr_json\n",
408 | "\n",
409 | " def normalize_attr( self ):\n",
410 | " max_attr_value = 20\n",
411 | " min_attr_value = 0\n",
412 | " regular_attr_sum = 30\n",
413 | " xs = [self.STR, self.SPD, self.VIT]\n",
414 | " current_sum = 0\n",
415 | " for i in range(3):\n",
416 | " xs[i] = min(max_attr_value, xs[i])\n",
417 | " xs[i] = max(min_attr_value, xs[i])\n",
418 | " current_sum += xs[i]\n",
419 | "\n",
420 | " if current_sum > regular_attr_sum:\n",
421 | " for i in range(3):\n",
422 | " xs[i] = round( xs[i] * regular_attr_sum / current_sum )\n",
423 | " elif current_sum < regular_attr_sum:\n",
424 | " for i in range(3):\n",
425 | " xs[i] = round( xs[i] * regular_attr_sum / current_sum )\n",
426 | "\n",
427 | " random_i = random.randint(0, 2)\n",
428 | " xs[random_i] = xs[random_i] + regular_attr_sum - sum(xs)\n",
429 | "\n",
430 | " self.STR = xs[0]\n",
431 | " self.SPD = xs[1]\n",
432 | " self.VIT = xs[2]\n",
433 | "\n",
434 | " def get_new_json(self):\n",
435 | " new_json = self.original_json\n",
436 | " new_json[\"STR\"] = self.STR\n",
437 | " new_json[\"SPD\"] = self.SPD\n",
438 | " new_json[\"VIT\"] = self.VIT\n",
439 | " new_json[\"hp\"] = self.hp\n",
440 | " new_json[\"skills\"] = self.skills\n",
441 | " return new_json\n",
442 | "\n",
443 | " def parsing_skill(self, skill_jsonl):\n",
444 | " skills = []\n",
445 | " lines = skill_jsonl.split(\"\\n\")\n",
446 | " for line in lines:\n",
447 | " if line.strip() == \"\":\n",
448 | " continue\n",
449 | " skill = json.loads(line)\n",
450 | " skills.append(skill)\n",
451 | " return skills\n",
452 | "\n",
453 | "\n"
454 | ]
455 | },
456 | {
457 | "cell_type": "code",
458 | "execution_count": 11,
459 | "metadata": {
460 | "id": "9MHcMooVUiuK"
461 | },
462 | "outputs": [],
463 | "source": [
464 | "from math import exp\n",
465 | "\n",
466 | "hit_map = {30: 131, 31: 131, 32: 131, 33: 131, 34: 131, 35: 120, 36: 112, 37: 107, 38: 103, 39: 100, 40: 97, 41: 95, 42: 93, 43: 91, 44: 89, 45: 87, 46: 86, 47: 85, 48: 83, 49: 82, 50: 81, 51: 80, 52: 79, 53: 78, 54: 77, 55: 76, 56: 75, 57: 74, 58: 73, 59: 72, 60: 71, 61: 70, 62: 69, 63: 69, 64: 68, 65: 67, 66: 66, 67: 65, 68: 65, 69: 64, 70: 63, 71: 63, 72: 62, 73: 61, 74: 61, 75: 60, 76: 59, 77: 59, 78: 58, 79: 58, 80: 57, 81: 57, 82: 56, 83: 55, 84: 55, 85: 54, 86: 54, 87: 53, 88: 53, 89: 52, 90: 52, 91: 52, 92: 51, 93: 51, 94: 50, 95: 50, 96: 49, 97: 49, 98: 49, 99: 48, 100: 48, 101: 47, 102: 47, 103: 47, 104: 46, 105: 46, 106: 46, 107: 45, 108: 45, 109: 44, 110: 44, 111: 44, 112: 43, 113: 43, 114: 43, 115: 43, 116: 42, 117: 42, 118: 42, 119: 41, 120: 41, 121: 41, 122: 40, 123: 40, 124: 40, 125: 40, 126: 39, 127: 39, 128: 39, 129: 39, 130: 38, 131: 38, 132: 38, 133: 38, 134: 37, 135: 37, 136: 37, 137: 37, 138: 36, 139: 36, 140: 36, 141: 36, 142: 36, 143: 35, 144: 35, 145: 35, 146: 35, 147: 34, 148: 34, 149: 34, 150: 34, 151: 34, 152: 33, 153: 33, 154: 33, 155: 33, 156: 33, 157: 33, 158: 32, 159: 32, 160: 32, 161: 32, 162: 32, 163: 31, 164: 31, 165: 31, 166: 31, 167: 31, 168: 31, 169: 30, 170: 30, 171: 30, 172: 30, 173: 30, 174: 30, 175: 30, 176: 29, 177: 29, 178: 29, 179: 29, 180: 29}\n",
467 | "\n",
468 | "min_damage = 34\n",
469 | "max_damage = 180\n",
470 | "\n",
471 | "class GameManager:\n",
472 | " def __init__(self, attr_json1, attr_json2, skill_jsonl1, skill_jsonl2):\n",
473 | " self.player1 = Player(attr_json1, skill_jsonl1)\n",
474 | " self.player2 = Player(attr_json2, skill_jsonl2)\n",
475 | "\n",
476 | " def run(self):\n",
477 | " speed_diff = self.player1.SPD - self.player2.SPD\n",
478 | " if speed_diff == 0:\n",
479 | " speed_diff = random.randint(0, 3)*2-3\n",
480 | "\n",
481 | "\n",
482 | " skill_id_1 = random.randint(0, len(self.player1.skills) - 1)\n",
483 | " dmg_1 = 60\n",
484 | " if skill_id_1 + skill_id_1 < len(self.player1.skills):\n",
485 | " dmg_1 = self.player1.major_damage\n",
486 | " else:\n",
487 | " dmg_1 = self.player1.secondary_damage\n",
488 | "\n",
489 | " skill_1_to_2 = self.player1.skills[skill_id_1]\n",
490 | " skill_1_to_2[\"dmg\"] = dmg_1\n",
491 | "\n",
492 | " skill_id_2 = random.randint(0, len(self.player2.skills) - 1)\n",
493 | " dmg_2 = 60\n",
494 | " if skill_id_2 + skill_id_2 < len(self.player2.skills):\n",
495 | " dmg_2 = self.player2.major_damage\n",
496 | " else:\n",
497 | " dmg_2 = self.player2.secondary_damage\n",
498 | "\n",
499 | " skill_2_to_1 = self.player2.skills[skill_id_2]\n",
500 | " skill_2_to_1[\"dmg\"] = dmg_2\n",
501 | "\n",
502 | " # skill_2_to_1 = random.choice(self.player2.skills)\n",
503 | "\n",
504 | " # print(skill_1_to_2)\n",
505 | " # print(skill_2_to_1)\n",
506 | "\n",
507 | " damage_1_to_2 = self.compute_damage(skill_1_to_2, self.player1, self.player2)\n",
508 | " damage_2_to_1 = self.compute_damage(skill_2_to_1, self.player2, self.player1)\n",
509 | "\n",
510 | " ratio_1_to_2 = self.compute_ratio(skill_1_to_2, self.player1, self.player2)\n",
511 | " ratio_2_to_1 = self.compute_ratio(skill_2_to_1, self.player2, self.player1)\n",
512 | "\n",
513 | " if_hitted_1_to_2 = random.random()*100.0 < ratio_1_to_2\n",
514 | " if_hitted_2_to_1 = random.random()*100.0 < ratio_2_to_1\n",
515 | "\n",
516 | " desc_1_to_2 = skill_1_to_2[\"description\"] if if_hitted_1_to_2 else skill_1_to_2[\"missing\"]\n",
517 | " desc_1_to_2 = desc_1_to_2.replace( \"[player]\",self.player1.name ).replace( \"[target]\", self.player2.name )\n",
518 | "\n",
519 | " if if_hitted_1_to_2:\n",
520 | " desc_1_to_2 += f\"造成了{round(damage_1_to_2) }的伤害。\"\n",
521 | " else:\n",
522 | " desc_1_to_2 += f\"{self.player2.name }躲了过去\"\n",
523 | "\n",
524 | " desc_2_to_1 = skill_2_to_1[\"description\"] if if_hitted_2_to_1 else skill_2_to_1[\"missing\"]\n",
525 | " desc_2_to_1 = desc_2_to_1.replace( \"[player]\",self.player2.name ).replace( \"[target]\", self.player1.name )\n",
526 | " if if_hitted_2_to_1:\n",
527 | " desc_2_to_1 += f\"造成了{round(damage_2_to_1) }的伤害。\"\n",
528 | " else:\n",
529 | " desc_2_to_1 += f\"{self.player1.name }躲了过去\"\n",
530 | "\n",
531 | " self.flag = \"continue\"\n",
532 | "\n",
533 | " ans_msg = []\n",
534 | "\n",
535 | " if self.player2.hp <= 0:\n",
536 | " ans_msg.append( (None, f\"{self.player2.name}战败了\"))\n",
537 | " return ans_msg, self.player1.get_new_json(), self.player2.get_new_json()\n",
538 | "\n",
539 | " if self.player1.hp <= 0:\n",
540 | " ans_msg.append( (f\"{self.player1.name}战败了\", None))\n",
541 | " return ans_msg, self.player1.get_new_json(), self.player2.get_new_json()\n",
542 | "\n",
543 | " if speed_diff > 0:\n",
544 | " if if_hitted_1_to_2:\n",
545 | " self.player2.hp -= damage_1_to_2\n",
546 | "\n",
547 | " ans_msg.append( (desc_1_to_2, None ) )\n",
548 | "\n",
549 | " if self.player2.hp > 0 and if_hitted_2_to_1:\n",
550 | " self.player1.hp -= damage_2_to_1\n",
551 | "\n",
552 | " if self.player2.hp > 0:\n",
553 | " ans_msg.append( (None, desc_2_to_1))\n",
554 | "\n",
555 | " else:\n",
556 | " if if_hitted_2_to_1:\n",
557 | " self.player1.hp -= damage_2_to_1\n",
558 | "\n",
559 | " ans_msg.append( (None, desc_2_to_1))\n",
560 | "\n",
561 | " if self.player1.hp > 0 and if_hitted_1_to_2:\n",
562 | " self.player2.hp -= damage_1_to_2\n",
563 | "\n",
564 | " if self.player1.hp > 0:\n",
565 | " ans_msg.append( (desc_1_to_2, None ) )\n",
566 | "\n",
567 | " if self.player2.hp<=0:\n",
568 | " ans_msg.append( (None, f\"{self.player2.name}战败了\"))\n",
569 | " self.flag = \"player1_win\"\n",
570 | " if self.player1.hp<=0:\n",
571 | " ans_msg.append( (f\"{self.player1.name}战败了\", None))\n",
572 | " self.flag = \"player2_win\"\n",
573 | "\n",
574 | " return ans_msg, self.player1.get_new_json(), self.player2.get_new_json()\n",
575 | "\n",
576 | " # default \"damage\": 60, \"hit\": 76,\n",
577 | " def compute_damage(self, skill, player, target):\n",
578 | " damage_ratio = skill[\"dmg\"]\n",
579 | " damage_ratio = max(min_damage, damage_ratio)\n",
580 | " damage_ratio = min(max_damage, min_damage)\n",
581 | " skill_damage = damage_ratio + player.STR * 2\n",
582 | " attack_diff = player.STR - target.VIT * 0.5\n",
583 | " damage = skill_damage * (1 + 0.95 * (-0.5 + 1.0 / (1.0 + exp(-attack_diff/ 6.0)) ) )\n",
584 | " return damage\n",
585 | "\n",
586 | " def compute_ratio(self, skill, player, target):\n",
587 | " damage_ratio = skill[\"dmg\"]\n",
588 | " damage_ratio = round(damage_ratio)\n",
589 | " damage_ratio = max(min_damage, damage_ratio)\n",
590 | " damage_ratio = min(max_damage, min_damage)\n",
591 | " skill_hit = hit_map[damage_ratio]\n",
592 | "\n",
593 | " speed_diff = player.SPD - target.SPD\n",
594 | " hit_factor = (-0.5 + 1.0 / (1.0 + exp(-speed_diff/ 6.0)) )/2.0 * max(30.0,skill_hit)\n",
595 | " # print(hit_factor)\n",
596 | " return hit_factor + skill_hit\n",
597 | "\n"
598 | ]
599 | },
600 | {
601 | "cell_type": "code",
602 | "execution_count": 12,
603 | "metadata": {
604 | "id": "xxzVIUwtdYx6"
605 | },
606 | "outputs": [],
607 | "source": [
608 | "ma_foo_answer = \"\"\"李鲁鲁,山东逍遥派的游戏角色,擅长人工智能傀儡术,以下是为你设计的两套武功和一套身法(招架)以及每套的四个招式名字:\n",
609 | "\n",
610 | "武功一:电脑幻影拳法\n",
611 | "这套武功利用人工智能傀儡术,创建虚拟幻影来欺骗对手,令其难以捉摸。\n",
612 | "\n",
613 | "电脑虚像拳 - 创造多个虚像,使对手难以分辨真伪。\n",
614 | "数据掌控击 - 利用数据流动的速度来快速攻击对手。\n",
615 | "模拟迷雾拳 - 释放模糊幻影,混淆对手的视线。\n",
616 | "程序化拳法 - 不断变化的攻击组合,让对手无法预测。\n",
617 | "武功二:智能预测刀法\n",
618 | "这套武功充分利用你的智能傀儡术,通过对对手的行为进行分析和预测,达到精准打击的效果。\n",
619 | "\n",
620 | "预测之刃 - 准确地预测对手的下一步行动,发动致命一击。\n",
621 | "数据漩涡斩 - 利用对手的动向,将其引导至陷阱,然后发动猛烈攻击。\n",
622 | "算法刀舞 - 刀法如算法一般精准,快速地切入对手的防线。\n",
623 | "智能反击剑 - 反击对手的招式,使其付出惨痛的代价。\n",
624 | "身法(招架):数码幻影步\n",
625 | "这套身法让你能够迅速回避对手的攻击,同时保持对局掌握主动权。\n",
626 | "\n",
627 | "数码闪避 - 迅速移动,如数码般闪烁,躲避对手的攻击。\n",
628 | "傀儡幻影步 - 创造虚假的身影,使对手无法锁定你的位置。\n",
629 | "数据跃迁 - 在一瞬间跳跃到对手的盲点,出其不意。\n",
630 | "逍遥之法 - 以逍遥派的身法融入自然,消除敌人的攻击威胁。\n",
631 | "希望这些武功和身法(招架)可以为你的李鲁鲁角色增添一些游戏中的精彩元素!\n",
632 | "\"\"\"\n",
633 | "\n",
634 | "attr_foo_answer = \"\"\"{\"name\": \"李鲁鲁\",\"STR\":5,\"SPD\":5,\"VIT\":5,\"description\": \"山东逍遥派的李鲁鲁,擅长人工智能傀儡术,善于提前预测对方的行动进行战斗\",\"weapon\": \"无\",\"major_martial_art\": \"人工智能傀儡术\",\"major_movements\": [\"预测之眼\", \"智慧编织\", \"虚实交融\", \"机巧纠缠\"],\"secondary_martial_art\": \"人工智能傀儡术\",\"secondary_movements\": [\"预测之眼\", \"智慧编织\", \"虚实交融\", \"机巧纠缠\"],\"footwork_and_body_method\": \"山水行云\"}\"\"\"\n",
635 | "\n",
636 | "attr_lilulu = \"\"\"{\n",
637 | " \"name\": \"李鲁鲁\",\n",
638 | " \"description\": \"山东逍遥派的游戏角色,擅长人工智能傀儡术\",\n",
639 | " \"weapon\": \"智能刀剑\",\n",
640 | " \"major_martial_art\": \"电脑幻影拳法\",\n",
641 | " \"major_movements\": [\"电脑虚像拳\", \"数据掌控击\", \"模拟迷雾拳\", \"程序化拳法\"],\n",
642 | " \"major_damage\": 75,\n",
643 | " \"secondary_martial_art\": \"智能预测刀法\",\n",
644 | " \"secondary_movements\": [\"预测之刃\", \"数据漩涡斩\", \"算法刀舞\", \"智能反击剑\"],\n",
645 | " \"secondary_damage\": 85,\n",
646 | " \"footwork_and_body_method\": \"数码幻影步\",\n",
647 | " \"STR\": 6,\n",
648 | " \"VIT\": 5,\n",
649 | " \"SPD\": 18\n",
650 | "}\n",
651 | "\"\"\"\n",
652 | "\n",
653 | "attr_lengziang = \"\"\"{\n",
654 | " \"name\": \"冷子昂\",\n",
655 | " \"description\": \"擅长冰系技能\",\n",
656 | " \"weapon\": \"冰刃\",\n",
657 | " \"major_martial_art\": \"冰霜寒刃功\",\n",
658 | " \"major_movements\": [\"冰刃斩破\", \"冰风流转\", \"冰龙穿云\", \"冰心彻骨\"],\n",
659 | " \"major_damage\": 80,\n",
660 | " \"secondary_martial_art\": \"冰封无影步\",\n",
661 | " \"secondary_movements\": [\"冰封幻影\", \"无影冻结\", \"冰刃闪耀\", \"冰封禅定\"],\n",
662 | " \"secondary_damage\": 70,\n",
663 | " \"footwork_and_body_method\": \"冰心护身法\",\n",
664 | " \"STR\": 8,\n",
665 | " \"VIT\": 6,\n",
666 | " \"SPD\": 15\n",
667 | "}\n",
668 | "\"\"\"\n",
669 | "\n",
670 | "json_str_huangrong = \"\"\"{\n",
671 | " \"name\": \"黄蓉\",\n",
672 | " \"description\": \"丐帮帮主黄蓉,擅长打狗棒法和落英神剑掌,身法为逍遥游。\",\n",
673 | " \"weapon\": \"棒、剑\",\n",
674 | " \"major_martial_art\": \"打狗棒法\",\n",
675 | " \"major_movements\": [\"狗啸山林\", \"棒影重重\", \"狗尾续貂\", \"狗急跳墙\"],\n",
676 | " \"major_damage\": 90,\n",
677 | " \"secondary_martial_art\": \"落英神剑掌\",\n",
678 | " \"secondary_movements\": [\"落英如雨\", \"神剑破空\", \"飞花流水\", \"剑指苍穹\"],\n",
679 | " \"secondary_damage\": 80,\n",
680 | " \"footwork_and_body_method\": \"逍遥游\",\n",
681 | " \"STR\": 15,\n",
682 | " \"VIT\": 10,\n",
683 | " \"SPD\": 18\n",
684 | "}\"\"\"\n",
685 | "\n",
686 | "\n",
687 | "skill_foo_desc = \"\"\"\n",
688 | "{\"招式\":\"预测之眼\",\"description\":\"[player]凝神聚气,双眼闪烁着深邃的智慧,一招“预测之眼”发动,仿佛未来已经显现在眼前,[player]能够精准预测[target]的下一步动作。\",\"missing\":\"[player]凝神聚气,双眼闪烁着深邃的智慧,一招“预测之眼”发动,仿佛未来已经显现在眼前,[target]的一举一动变得难以捉摸。\"}\n",
689 | "{\"招式\":\"智慧编织\",\"description\":\"[player]手中的线缠绕着[target],编织成一个巧妙的陷阱,一招“智慧编织”完成,如同织女编织云锦,[target]的行动受到了限制。\",\"missing\":\"[player]手中的线缠绕着,编织成一个巧妙的陷阱,一招“智慧编织”完成,[target]似乎被某种力量限制住了行动。\"}\n",
690 | "{\"招式\":\"虚实交融\",\"description\":\"[player]身形忽明忽暗,虚实难辨,一招“虚实交融”使出,仿佛有数个[player]一同出招,[target]不知所措。\",\"missing\":\"[player]身形忽明忽暗,虚实难辨,一招“虚实交融”使出,[target]眼前忽然出现了一片幻影,令其感到迷茫。\"}\n",
691 | "{\"招式\":\"机巧纠缠\",\"description\":\"[player]运用机巧傀儡术,手中的人工智能傀儡纷纷扑向[target],一招“机巧纠缠”展开,[target]被困在了傀儡的包围中。\",\"missing\":\"[player]运用机巧傀儡术,手中的人工智能傀儡纷纷扑向,一招“机巧纠缠”展开,[target]四面八方都是傀儡的身影,形势险恶。\"}\n",
692 | "{\"招式\":\"预测之眼\",\"description\":\"[player]凝神聚气,双眼闪烁着深邃的智慧,一招“预测之眼”发动,仿佛未来已经显现在眼前,[player]能够精准预测[target]的下一步动作。\",\"missing\":\"[player]凝神聚气,双眼闪烁着深邃的智慧,一招“预测之眼”发动,仿佛未来已经显现在眼前,[target]的一举一动变得难以捉摸。\"}\n",
693 | "{\"招式\":\"智慧编织\",\"description\":\"[player]手中的线缠绕着[target],编织成一个巧妙的陷阱,一招“智慧编织”完成,如同织女编织云锦,[target]的行动受到了限制。\",\"missing\":\"[player]手中的线缠绕着,编织成一个巧妙的陷阱,一招“智慧编织”完成,[target]似乎被某种力量限制住了行动。\"}\n",
694 | "{\"招式\":\"虚实交融\",\"description\":\"[player]身形忽明忽暗,虚实难辨,一招“虚实交融”使出,仿佛有数个[player]一同出招,[target]不知所措。\",\"missing\":\"[player]身形忽明忽暗,虚实难辨,一招“虚实交融”使出,[target]眼前忽然出现了一片幻影,令其感到迷茫。\"}\n",
695 | "{\"招式\":\"机巧纠缠\",\"description\":\"[player]运用机巧傀儡术,手中的人工智能傀儡纷纷扑向[target],一招“机巧纠缠”展开,[target]被困在了傀儡的包围中。\",\"missing\":\"[player]运用机巧傀儡术,手中的人工智能傀儡纷纷扑向,一招“机巧纠缠”展开,[target]四面八方都是傀儡的身影,形势险恶。\"}\n",
696 | "\"\"\"\n",
697 | "\n",
698 | "skill_lilulu = \"\"\"\n",
699 | "{\"招式\":\"电脑虚像拳\",\"description\":\"[player]运用电脑幻影拳法,双拳虚虚实实,制造出多个虚像,令[target]难以分辨真伪,招招不离其身。\",\"missing\":\"[player]运用电脑幻影拳法,双拳虚虚实实,制造出多个虚像,令[target]难以分辨真伪。\"}\n",
700 | "{\"招式\":\"数据掌控击\",\"description\":\"[player]施展数据掌控击,利用数据流动的速度,犹如电光闪烁,快速攻击[target],剑招迅猛,如电一般。\",\"missing\":\"[player]施展数据掌控击,利用数据流动的速度,犹如电光闪烁,快速攻击[target],剑招迅猛。\"}\n",
701 | "{\"招式\":\"模拟迷雾拳\",\"description\":\"[player]施展模拟迷雾拳,释放出模糊幻影,混淆[target]的视线,令其难以辨别攻击方向。\",\"missing\":\"[player]施展模拟迷雾拳,释放出模糊幻影,混淆[target]的视线,令其难以辨别攻击方向。\"}\n",
702 | "{\"招式\":\"程序化拳法\",\"description\":\"[player]运用程序化拳法,以不断变化的攻击组合,让[target]难以预测招式,时而快时而慢,攻击变幻莫测。\",\"missing\":\"[player]运用程序化拳法,以不断变化的攻击组合,让[target]难以预测招式,攻击变幻莫测。\"}\n",
703 | "{\"招式\":\"预测之刃\",\"description\":\"[player]使出预测之刃,准确地预测[target]的下一步行动,犹如镜中水月,剑锋准确地击中[target]的要害。\",\"missing\":\"[player]使出预测之刃,准确地预测[target]的下一步行动,犹如镜中水月,剑锋迅速挥出。\"}\n",
704 | "{\"招式\":\"数据漩涡斩\",\"description\":\"[player]施展数据漩涡斩,利用[target]的动向,将其引导至剑刃之下,然后发动猛烈攻击,犹如漩涡将[target]吸入其中。\",\"missing\":\"[player]施展数据漩涡斩,利用[target]的动向,将其引导至剑刃之下,然后发动猛烈攻击,剑招异常犀利。\"}\n",
705 | "{\"招式\":\"算法刀舞\",\"description\":\"[player]挥舞着长剑,使出算法刀舞,刀法如算法一般精准,快速地切入[target]的防线,剑锋连续不断地斩向[target]。\",\"missing\":\"[player]挥舞着长剑,使出算法刀舞,刀法如算法一般精准,快速地切入[target]的防线,剑招变化多端。\"}\n",
706 | "{\"招式\":\"智能反击剑\",\"description\":\"[player]运用智能反击剑,反击[target]的招式,使其付出惨痛的代价,一瞬间的犹豫就足以让[target]受伤。\",\"missing\":\"[player]运用智能反击剑,反击[target]的招式,使其陷入困境,一瞬间的犹豫足以让[target]付出代价。\"}\n",
707 | "\"\"\"\n",
708 | "\n",
709 | "skill_lengziang = \"\"\"\n",
710 | "{\"招式\":\"冰刃斩破\",\"description\":\"[player]聚集冰之力量于剑上,使出冰刃斩破,剑锋犹如寒冰之刃斩向[target]的要害部位,寒气逼人,剑光炽烈。\",\"missing\":\"[player]聚集冰之力量于剑上,使出冰刃斩破,剑锋犹如寒冰之刃,闪电般挥出。\"}\n",
711 | "{\"招式\":\"冰风流转\",\"description\":\"[player]身体如风一般旋转,同时释放出冰风刃,打击周围的敌人,冷飕飕的寒风环绕,[target]身不由己地被吹向一旁。\",\"missing\":\"[player]身体如风一般旋转,同时释放出冰风刃,冷飕飕的寒风环绕,风刃在[target]周围飞舞。\"}\n",
712 | "{\"招式\":\"冰龙穿云\",\"description\":\"[player]召唤出一条冰龙,冰龙穿越云层直扑[target],寒冰之力凝聚在龙爪之上,将[target]冻结一切,一切都难以抵挡。\",\"missing\":\"[player]召唤出一条冰龙,冰龙穿越云层,龙爪直扑[target],寒冰之力凝聚在龙爪之上,寒意森然。\"}\n",
713 | "{\"招式\":\"冰心彻骨\",\"description\":\"[player]凝聚冰之力于手,一触即可让[target]骨骼寒冷,动弹不得,彻底冰封,剑锋轻轻触及[target],寒意透骨。\",\"missing\":\"[player]凝聚冰之力于手,一触即可让[target]骨骼寒冷,动弹不得,寒气透骨,剑锋轻轻触及[target]。\"}\n",
714 | "{\"招式\":\"冰封幻影\",\"description\":\"[player]运用冰封无影步,快速移动,留下一道冰封的幻影,使[target]无法辨别真伪,幻影与实体交替出现,令[target]不知所措。\",\"missing\":\"[player]运用冰封无影步,快速移动,留下一道冰封的幻影,使[target]无法辨别真伪。\"}\n",
715 | "{\"招式\":\"无影冻结\",\"description\":\"[player]以极快的速度接近[target],然后冻结[target]的动作,使其陷入无法自拔的状态,如同身陷冰封之中,动弹不得。\",\"missing\":\"[player]以极快的速度接近[target],然后冻结[target]的动作,使其陷入无法自拔的状态。\"}\n",
716 | "{\"招式\":\"冰刃闪耀\",\"description\":\"[player]利用冰之能量,瞬间闪现至[target]身边,发动迅猛的攻击,剑锋如星光般闪烁,将[target]包围其中。\",\"missing\":\"[player]利用冰之能量,瞬间闪现至[target]身边,发动迅猛的攻击,剑锋如星光般闪烁。\"}\n",
717 | "{\"招式\":\"冰封禅定\",\"description\":\"[player]静心冥想,将身体冰封,使自己无法被[target]察觉,达到不可捉摸的状态,如同融入冰封禅定之中。\",\"missing\":\"[player]静心冥想,将身体冰封,使自己无法被[target]察觉,达到不可捉摸的状态。\"}\n",
718 | "\"\"\"\n",
719 | "\n",
720 | "\n",
721 | "skill_huangrong = \"\"\"\n",
722 | "{\"招式\": \"狗啸山林\", \"description\": \"[player]手中长棒一挥,发出一声凄厉的狗啸,棒影如山林般扑向[target]\", \"missing\": \"[player]手中长棒一挥,发出一声凄厉的狗啸,棒影如山林般扑向[target]\"}\n",
723 | "{\"招式\": \"棒影重重\", \"description\": \"[player]身形连转,手中长棒化作无数道棒影,重重叠叠地向[target]砸去\", \"missing\": \"[player]身形连转,手中长棒化作无数道棒影,重重叠叠地向[target]砸去\"}\n",
724 | "{\"招式\": \"狗尾续貂\", \"description\": \"[player]手中长棒如狗尾续貂般灵动,连续变换方向,向[target]连续攻击\", \"missing\": \"[player]手中长棒如狗尾续貂般灵动,连续变换方向,向[target]连续攻击\"}\n",
725 | "{\"招式\": \"狗急跳墙\", \"description\": \"[player]猛地一跃,手中长棒带起狂风,如狗急跳墙般向[target]砸去\", \"missing\": \"[player]猛地一跃,手中长棒带起狂风,如狗急跳墙般向[target]砸去\"}\n",
726 | "{\"招式\": \"落英如雨\", \"description\": \"[player]身形一闪,双掌连续拍出,犹如漫天飘落的落英,掌风凌厉,瞬间覆盖[target]周身\", \"missing\": \"[player]身形一闪,双掌连续拍出,犹如漫天飘落的落英,掌风凌厉,向[target]周身袭去\"}\n",
727 | "{\"招式\": \"神剑破空\", \"description\": \"[player]手中剑光闪烁,一剑刺出,剑气凌厉无比,犹如神剑破开虚空,直指[target]要害\", \"missing\": \"[player]手中剑光闪烁,一剑刺出,剑气凌厉无比,直向[target]要害刺去\"}\n",
728 | "{\"招式\": \"飞花流水\", \"description\": \"[player]身形如飞,双掌连续拍击,掌风如流水般连绵不绝,将[target]团团围住\", \"missing\": \"[player]身形如飞,双掌连续拍击,掌风如流水般连绵不绝,向[target]团团包围\"}\n",
729 | "{\"招式\": \"剑指苍穹\", \"description\": \"[player]手中长剑一指,剑光直冲云霄,气势如虹,剑指直指苍穹,威力惊人\", \"missing\": \"[player]手中长剑一指,剑光直冲云霄,气势如虹,直指苍穹\"}\n",
730 | "\"\"\""
731 | ]
732 | },
733 | {
734 | "cell_type": "code",
735 | "execution_count": 13,
736 | "metadata": {
737 | "colab": {
738 | "base_uri": "https://localhost:8080/"
739 | },
740 | "id": "YFXLzKq2ek-8",
741 | "outputId": "48ac1639-9172-4fb6-9ddd-f8a2d4298e47"
742 | },
743 | "outputs": [
744 | {
745 | "output_type": "stream",
746 | "name": "stdout",
747 | "text": [
748 | "{'name': '李鲁鲁', 'STR': 5, 'SPD': 5, 'VIT': 5, 'description': '山东逍遥派的李鲁鲁,擅长人工智能傀儡术,善于提前预测对方的行动进行战斗', 'weapon': '无', 'major_martial_art': '人工智能傀儡术', 'major_movements': ['预测之眼', '智慧编织', '虚实交融', '机巧纠缠'], 'secondary_martial_art': '人工智能傀儡术', 'secondary_movements': ['预测之眼', '智慧编织', '虚实交融', '机巧纠缠'], 'footwork_and_body_method': '山水行云'}\n"
749 | ]
750 | }
751 | ],
752 | "source": [
753 | "import json\n",
754 | "\n",
755 | "json_data = json.loads(attr_foo_answer)\n",
756 | "\n",
757 | "print(json_data)\n",
758 | "\n",
759 | "json_lilulu = json.loads(attr_lilulu)\n",
760 | "json_lengziang = json.loads(attr_lengziang)\n",
761 | "\n"
762 | ]
763 | },
764 | {
765 | "cell_type": "code",
766 | "source": [
767 | "print(attr_lilulu)"
768 | ],
769 | "metadata": {
770 | "colab": {
771 | "base_uri": "https://localhost:8080/"
772 | },
773 | "id": "S_XuZjmHUxrJ",
774 | "outputId": "1e2eba34-9bfe-4592-dc38-04ed3332396c"
775 | },
776 | "execution_count": 14,
777 | "outputs": [
778 | {
779 | "output_type": "stream",
780 | "name": "stdout",
781 | "text": [
782 | "{\n",
783 | " \"name\": \"李鲁鲁\",\n",
784 | " \"description\": \"山东逍遥派的游戏角色,擅长人工智能傀儡术\",\n",
785 | " \"weapon\": \"智能刀剑\",\n",
786 | " \"major_martial_art\": \"电脑幻影拳法\",\n",
787 | " \"major_movements\": [\"电脑虚像拳\", \"数据掌控击\", \"模拟迷雾拳\", \"程序化拳法\"],\n",
788 | " \"major_damage\": 75,\n",
789 | " \"secondary_martial_art\": \"智能预测刀法\",\n",
790 | " \"secondary_movements\": [\"预测之刃\", \"数据漩涡斩\", \"算法刀舞\", \"智能反击剑\"],\n",
791 | " \"secondary_damage\": 85,\n",
792 | " \"footwork_and_body_method\": \"数码幻影步\",\n",
793 | " \"STR\": 6,\n",
794 | " \"VIT\": 5,\n",
795 | " \"SPD\": 18\n",
796 | "}\n",
797 | "\n"
798 | ]
799 | }
800 | ]
801 | },
802 | {
803 | "cell_type": "code",
804 | "execution_count": 15,
805 | "metadata": {
806 | "colab": {
807 | "base_uri": "https://localhost:8080/"
808 | },
809 | "id": "ID7Q03RFSRfD",
810 | "outputId": "b3a055bd-cd3f-4b38-e971-2ce5dbbd4ea7"
811 | },
812 | "outputs": [
813 | {
814 | "output_type": "stream",
815 | "name": "stdout",
816 | "text": [
817 | "10\n",
818 | "10\n",
819 | "10\n",
820 | "{'name': '李鲁鲁', 'STR': 10, 'SPD': 10, 'VIT': 10, 'description': '山东逍遥派的李鲁鲁,擅长人工智能傀儡术,善于提前预测对方的行动进行战斗', 'weapon': '无', 'major_martial_art': '人工智能傀儡术', 'major_movements': ['预测之眼', '智慧编织', '虚实交融', '机巧纠缠'], 'secondary_martial_art': '人工智能傀儡术', 'secondary_movements': ['预测之眼', '智慧编织', '虚实交融', '机巧纠缠'], 'footwork_and_body_method': '山水行云', 'hp': 600, 'skills': [{'招式': '预测之眼', 'description': '[player]凝神聚气,双眼闪烁着深邃的智慧,一招“预测之眼”发动,仿佛未来已经显现在眼前,[player]能够精准预测[target]的下一步动作。', 'missing': '[player]凝神聚气,双眼闪烁着深邃的智慧,一招“预测之眼”发动,仿佛未来已经显现在眼前,[target]的一举一动变得难以捉摸。'}, {'招式': '智慧编织', 'description': '[player]手中的线缠绕着[target],编织成一个巧妙的陷阱,一招“智慧编织”完成,如同织女编织云锦,[target]的行动受到了限制。', 'missing': '[player]手中的线缠绕着,编织成一个巧妙的陷阱,一招“智慧编织”完成,[target]似乎被某种力量限制住了行动。'}, {'招式': '虚实交融', 'description': '[player]身形忽明忽暗,虚实难辨,一招“虚实交融”使出,仿佛有数个[player]一同出招,[target]不知所措。', 'missing': '[player]身形忽明忽暗,虚实难辨,一招“虚实交融”使出,[target]眼前忽然出现了一片幻影,令其感到迷茫。'}, {'招式': '机巧纠缠', 'description': '[player]运用机巧傀儡术,手中的人工智能傀儡纷纷扑向[target],一招“机巧纠缠”展开,[target]被困在了傀儡的包围中。', 'missing': '[player]运用机巧傀儡术,手中的人工智能傀儡纷纷扑向,一招“机巧纠缠”展开,[target]四面八方都是傀儡的身影,形势险恶。'}, {'招式': '预测之眼', 'description': '[player]凝神聚气,双眼闪烁着深邃的智慧,一招“预测之眼”发动,仿佛未来已经显现在眼前,[player]能够精准预测[target]的下一步动作。', 'missing': '[player]凝神聚气,双眼闪烁着深邃的智慧,一招“预测之眼”发动,仿佛未来已经显现在眼前,[target]的一举一动变得难以捉摸。'}, {'招式': '智慧编织', 'description': '[player]手中的线缠绕着[target],编织成一个巧妙的陷阱,一招“智慧编织”完成,如同织女编织云锦,[target]的行动受到了限制。', 'missing': '[player]手中的线缠绕着,编织成一个巧妙的陷阱,一招“智慧编织”完成,[target]似乎被某种力量限制住了行动。'}, {'招式': '虚实交融', 'description': '[player]身形忽明忽暗,虚实难辨,一招“虚实交融”使出,仿佛有数个[player]一同出招,[target]不知所措。', 'missing': '[player]身形忽明忽暗,虚实难辨,一招“虚实交融”使出,[target]眼前忽然出现了一片幻影,令其感到迷茫。'}, {'招式': '机巧纠缠', 'description': '[player]运用机巧傀儡术,手中的人工智能傀儡纷纷扑向[target],一招“机巧纠缠”展开,[target]被困在了傀儡的包围中。', 'missing': '[player]运用机巧傀儡术,手中的人工智能傀儡纷纷扑向,一招“机巧纠缠”展开,[target]四面八方都是傀儡的身影,形势险恶。'}]}\n",
821 | "389.81778459917484\n",
822 | "428.64852722647896\n",
823 | "329.6355691983497\n",
824 | "377.2970544529579\n",
825 | "269.4533537975245\n",
826 | "325.9455816794369\n",
827 | "8\n"
828 | ]
829 | }
830 | ],
831 | "source": [
832 | "player = Player( json_data, skill_foo_desc )\n",
833 | "print(player.STR)\n",
834 | "print(player.SPD)\n",
835 | "print(player.VIT)\n",
836 | "print(player.get_new_json())\n",
837 | "\n",
838 | "game_manager = GameManager(json_lilulu, json_lengziang, skill_lilulu,skill_lengziang)\n",
839 | "\n",
840 | "game_manager.run()\n",
841 | "\n",
842 | "print(game_manager.player1.hp)\n",
843 | "print(game_manager.player2.hp)\n",
844 | "\n",
845 | "game_manager.run()\n",
846 | "\n",
847 | "print(game_manager.player1.hp)\n",
848 | "print(game_manager.player2.hp)\n",
849 | "\n",
850 | "\n",
851 | "game_manager.run()\n",
852 | "\n",
853 | "print(game_manager.player1.hp)\n",
854 | "print(game_manager.player2.hp)\n",
855 | "\n",
856 | "\n",
857 | "output_data = player.get_new_json()\n",
858 | "print(len(output_data[\"skills\"]))\n",
859 | "\n",
860 | "\n"
861 | ]
862 | },
863 | {
864 | "cell_type": "code",
865 | "execution_count": 16,
866 | "metadata": {
867 | "colab": {
868 | "base_uri": "https://localhost:8080/"
869 | },
870 | "id": "7wH8j7TcjNA9",
871 | "outputId": "3a5c91d3-050c-4417-e754-3416b404ff5e"
872 | },
873 | "outputs": [
874 | {
875 | "output_type": "stream",
876 | "name": "stdout",
877 | "text": [
878 | "{'招式': '电脑虚像拳', 'description': '[player]运用电脑幻影拳法,双拳虚虚实实,制造出多个虚像,令[target]难以分辨真伪,招招不离其身。', 'missing': '[player]运用电脑幻影拳法,双拳虚虚实实,制造出多个虚像,令[target]难以分辨真伪。'}\n",
879 | "{'招式': '冰龙穿云', 'description': '[player]召唤出一条冰龙,冰龙穿越云层直扑[target],寒冰之力凝聚在龙爪之上,将[target]冻结一切,一切都难以抵挡。', 'missing': '[player]召唤出一条冰龙,冰龙穿越云层,龙爪直扑[target],寒冰之力凝聚在龙爪之上,寒意森然。'}\n"
880 | ]
881 | }
882 | ],
883 | "source": [
884 | "print(random.choice(game_manager.player1.skills))\n",
885 | "print(random.choice(game_manager.player2.skills))"
886 | ]
887 | },
888 | {
889 | "cell_type": "markdown",
890 | "metadata": {
891 | "id": "lju4g7rxVu2z"
892 | },
893 | "source": [
894 | "# 实现人物库和elo-rating"
895 | ]
896 | },
897 | {
898 | "cell_type": "markdown",
899 | "metadata": {
900 | "id": "Doke6NRYWWSP"
901 | },
902 | "source": [
903 | "考虑到因为放到hugging face上,人物也是不会记录的\n",
904 | "\n",
905 | "所以这里我们只记录人物的attr_json和skill jsonl,不记录其他额外的消息"
906 | ]
907 | },
908 | {
909 | "cell_type": "code",
910 | "execution_count": null,
911 | "metadata": {
912 | "id": "0V4T5OpYWjXX"
913 | },
914 | "outputs": [],
915 | "source": [
916 | "# from google.colab import drive\n",
917 | "# drive.mount('/content/drive')"
918 | ]
919 | },
920 | {
921 | "cell_type": "code",
922 | "execution_count": 18,
923 | "metadata": {
924 | "id": "k5W-MfrmWtYa"
925 | },
926 | "outputs": [],
927 | "source": [
928 | "fighter_save_name = '/content/LuotuoFighter.txt'\n",
929 | "\n",
930 | "import os\n",
931 | "\n",
932 | "datas = []\n",
933 | "\n",
934 | "if not os.path.exists(fighter_save_name):\n",
935 | " data = {\n",
936 | " \"name\":\"李鲁鲁\",\n",
937 | " \"attr_str\":attr_lilulu,\n",
938 | " \"skills\":skill_lilulu\n",
939 | " }\n",
940 | " datas.append(data)\n",
941 | " data = {\n",
942 | " \"name\":\"冷子昂\",\n",
943 | " \"attr_str\":attr_lengziang,\n",
944 | " \"skills\":skill_lengziang\n",
945 | " }\n",
946 | " datas.append(data)\n",
947 | " data = {\n",
948 | " \"name\":\"黄蓉\",\n",
949 | " \"attr_str\":json_str_huangrong,\n",
950 | " \"skills\":skill_huangrong\n",
951 | " }\n",
952 | " datas.append(data)\n",
953 | " with open(fighter_save_name, 'w', encoding=\"utf-8\") as f:\n",
954 | " for data in datas:\n",
955 | " f.write(json.dumps(data,ensure_ascii=False) + \"\\n\")\n",
956 | "else:\n",
957 | " with open(fighter_save_name, 'r', encoding=\"utf-8\") as f:\n",
958 | " for line in f.readlines():\n",
959 | " data = json.loads(line)\n",
960 | " datas.append(data)\n",
961 | "\n",
962 | "fighter_data = datas"
963 | ]
964 | },
965 | {
966 | "cell_type": "markdown",
967 | "metadata": {
968 | "id": "YuAVU6rC7Ae6"
969 | },
970 | "source": [
971 | "随着datas初始化elorating表"
972 | ]
973 | },
974 | {
975 | "cell_type": "code",
976 | "execution_count": 19,
977 | "metadata": {
978 | "colab": {
979 | "base_uri": "https://localhost:8080/"
980 | },
981 | "id": "W0wXVSbNwiy5",
982 | "outputId": "b71eca74-a9be-40ad-bf65-25eed2e3c0ec"
983 | },
984 | "outputs": [
985 | {
986 | "output_type": "stream",
987 | "name": "stdout",
988 | "text": [
989 | "{\n",
990 | " \"name\": \"李鲁鲁\",\n",
991 | " \"description\": \"山东逍遥派的游戏角色,擅长人工智能傀儡术\",\n",
992 | " \"weapon\": \"智能刀剑\",\n",
993 | " \"major_martial_art\": \"电脑幻影拳法\",\n",
994 | " \"major_movements\": [\"电脑虚像拳\", \"数据掌控击\", \"模拟迷雾拳\", \"程序化拳法\"],\n",
995 | " \"major_damage\": 75,\n",
996 | " \"secondary_martial_art\": \"智能预测刀法\",\n",
997 | " \"secondary_movements\": [\"预测之刃\", \"数据漩涡斩\", \"算法刀舞\", \"智能反击剑\"],\n",
998 | " \"secondary_damage\": 85,\n",
999 | " \"footwork_and_body_method\": \"数码幻影步\",\n",
1000 | " \"STR\": 6,\n",
1001 | " \"VIT\": 5,\n",
1002 | " \"SPD\": 18\n",
1003 | "}\n",
1004 | "\n"
1005 | ]
1006 | }
1007 | ],
1008 | "source": [
1009 | "print(fighter_data[0][\"attr_str\"])"
1010 | ]
1011 | },
1012 | {
1013 | "cell_type": "code",
1014 | "execution_count": 20,
1015 | "metadata": {
1016 | "id": "2JJ7NV_F7fin"
1017 | },
1018 | "outputs": [],
1019 | "source": [
1020 | "elo_table = {}\n",
1021 | "\n",
1022 | "def get_unique_from_data( data ):\n",
1023 | " name = data[\"name\"]\n",
1024 | " json_data = json.loads(data[\"attr_str\"])\n",
1025 | " return get_unique_from_json( name , json_data )\n",
1026 | "\n",
1027 | "def get_unique_from_json( name , json_data ):\n",
1028 | " if \"STR\" in json_data and \"VIT\" in json_data and \"SPD\" in json_data and \"major_damage\" in json_data and \"secondary_damage\" in json_data:\n",
1029 | " return name + \"_\" + str(json_data[\"major_damage\"]) + \"_\" + str(json_data[\"secondary_damage\"])\n",
1030 | " else:\n",
1031 | " return None\n",
1032 | "\n",
1033 | "\n",
1034 | "unique_to_score = {}\n",
1035 | "name_to_top_unique = {}\n",
1036 | "\n",
1037 | "from math import exp\n",
1038 | "\n",
1039 | "elo_start = 1200\n",
1040 | "elo_K = 15\n",
1041 | "\n",
1042 | "for data in fighter_data:\n",
1043 | " unique_name = get_unique_from_data(data)\n",
1044 | " score = elo_start\n",
1045 | " unique_to_score[ unique_name ] = elo_start\n",
1046 | " name = data[\"name\"]\n",
1047 | "\n",
1048 | " name_to_top_unique[name] = unique_name\n",
1049 | "\n",
1050 | "def get_rank_str(top_n = 20):\n",
1051 | " global unique_to_score\n",
1052 | " global name_to_top_unique\n",
1053 | "\n",
1054 | " score_name_pair = []\n",
1055 | " for name in name_to_top_unique:\n",
1056 | " unique = name_to_top_unique[name]\n",
1057 | " score = unique_to_score[unique]\n",
1058 | " score_name_pair.append((unique, score))\n",
1059 | "\n",
1060 | " top_n = min(top_n, len(name_to_top_unique))\n",
1061 | " score_name_pair.sort(key=lambda x: x[1], reverse=True)\n",
1062 | " ans = \"\"\n",
1063 | " for i in range(top_n):\n",
1064 | " name = score_name_pair[i][0].split(\"_\")[0]\n",
1065 | " ans += f\"第{i+1}名\" + name + \" - \" + str(round(score_name_pair[i][1] )) + \" | \"\n",
1066 | "\n",
1067 | " return ans\n",
1068 | "\n",
1069 | "def update_elo( winner_unique, loser_unique ):\n",
1070 | " print( winner_unique + \" wins \" + loser_unique)\n",
1071 | " update_winner = True\n",
1072 | " update_loser = True\n",
1073 | "\n",
1074 | " global unique_to_score\n",
1075 | " global name_to_top_unique\n",
1076 | "\n",
1077 | " if winner_unique not in unique_to_score:\n",
1078 | " unique_to_score[winner_unique] = elo_start\n",
1079 | " update_loser = False\n",
1080 | "\n",
1081 | " if loser_unique not in unique_to_score:\n",
1082 | " unique_to_score[loser_unique] = elo_start\n",
1083 | "\n",
1084 | " Ra = unique_to_score[winner_unique]\n",
1085 | " Rb = unique_to_score[loser_unique]\n",
1086 | "\n",
1087 | " Ea = 1 / (1 + exp((Rb - Ra) / 400))\n",
1088 | " Eb = 1 / (1 + exp((Ra - Rb) / 400))\n",
1089 | " Sa = 1\n",
1090 | " Sb = 0\n",
1091 | " unique_to_score[winner_unique] = Ra + elo_K*(Sa - Ea)\n",
1092 | " unique_to_score[loser_unique] = Rb + elo_K*(Sb - Eb)\n",
1093 | "\n",
1094 | " winner_name = winner_unique.split(\"_\")[0]\n",
1095 | "\n",
1096 | " if winner_name not in name_to_top_unique:\n",
1097 | " name_to_top_unique[ winner_name ] = winner_unique\n",
1098 | "\n",
1099 | " winner_unique_on_rank = name_to_top_unique[ winner_name ]\n",
1100 | " if unique_to_score[winner_unique] > unique_to_score[winner_unique_on_rank]:\n",
1101 | " name_to_top_unique[ winner_name ] = winner_unique\n"
1102 | ]
1103 | },
1104 | {
1105 | "cell_type": "code",
1106 | "execution_count": 21,
1107 | "metadata": {
1108 | "id": "19sf5O_dYD6I"
1109 | },
1110 | "outputs": [],
1111 | "source": [
1112 | "def get_random_fighter():\n",
1113 | " global fighter_data\n",
1114 | " return random.choice(fighter_data)\n",
1115 | "\n",
1116 | "def searching_fighter(name):\n",
1117 | " global fighter_data\n",
1118 | " for data in fighter_data:\n",
1119 | " if data[\"name\"] == name:\n",
1120 | " return data\n",
1121 | " return get_random_fighter()\n",
1122 | "\n",
1123 | "def add_fighter(attr_json_str, skill_jsonl):\n",
1124 | " attr_json = json.loads(attr_json_str)\n",
1125 | " if \"skills\" in attr_json:\n",
1126 | " del attr_json[\"skills\"]\n",
1127 | " if \"hp\" in attr_json:\n",
1128 | " del attr_json[\"hp\"]\n",
1129 | "\n",
1130 | " new_attr_json_str = json.dumps(attr_json,ensure_ascii=False)\n",
1131 | "\n",
1132 | " global fighter_data\n",
1133 | " name = attr_json[\"name\"]\n",
1134 | "\n",
1135 | " data = {\n",
1136 | " \"name\":name,\n",
1137 | " \"attr_str\":new_attr_json_str,\n",
1138 | " \"skills\":skill_jsonl\n",
1139 | " }\n",
1140 | " fighter_data.append(data)\n",
1141 | " # print(json.dumps(data,ensure_ascii=False) )\n",
1142 | " with open(fighter_save_name, 'a', encoding=\"utf-8\") as f:\n",
1143 | " f.write(json.dumps(data,ensure_ascii=False) + \"\\n\")\n"
1144 | ]
1145 | },
1146 | {
1147 | "cell_type": "markdown",
1148 | "metadata": {
1149 | "id": "-3t0_rtrbqCL"
1150 | },
1151 | "source": [
1152 | "## 实现foo函数\n",
1153 | "\n",
1154 | "我考虑用两个类 一个类负责生成和检查格式 一个类负责战斗\n",
1155 | "\n",
1156 | "- [x] 实现姓名、描述到功法名字的生成\n",
1157 | "- [x] 实现功法名字到功法细节描述的生成\n",
1158 | "- [x] 随机武侠属性\n",
1159 | "- [x] 战斗类,读取两个角色,进行一回合的战斗"
1160 | ]
1161 | },
1162 | {
1163 | "cell_type": "code",
1164 | "execution_count": 22,
1165 | "metadata": {
1166 | "id": "TAEfk4isUBQH"
1167 | },
1168 | "outputs": [],
1169 | "source": [
1170 | "import gradio as gr\n",
1171 | "import copy\n",
1172 | "\n",
1173 | "def get_attr_str_short( attr_json ):\n",
1174 | " ans = \"力量:\" + str(attr_json[\"STR\"]) + \"\\n体质:\" + str(attr_json[\"VIT\"]) + \"\\n速度:\" + str(attr_json[\"SPD\"])\n",
1175 | " return ans\n",
1176 | "\n",
1177 | "def get_skill_str_short( attr_json ):\n",
1178 | " ans = attr_json[\"major_martial_art\"] + \":\\n\"\n",
1179 | " for skill in attr_json[\"major_movements\"]:\n",
1180 | " ans += skill + \"-\"\n",
1181 | " ans += \"\\n\" + attr_json[\"secondary_martial_art\"] + \":\\n\"\n",
1182 | " for skill in attr_json[\"secondary_movements\"]:\n",
1183 | " ans += skill + \"-\"\n",
1184 | " ans += \"\\n 防御:\" + attr_json[\"footwork_and_body_method\"]\n",
1185 | " return ans\n",
1186 | "\n",
1187 | "def generate_ma(name, desc,display_board):\n",
1188 | "\n",
1189 | " if name.strip() == \"\":\n",
1190 | " return \"\", \"\", \"\", \"\" ,display_board, \"角色名不能为空,输入角色名后生成功法或者创建角色\"\n",
1191 | "\n",
1192 | " status = \"请为角色进一步生成详细功法\"\n",
1193 | "\n",
1194 | " # 应该是用name和desc先生成出一个描述\n",
1195 | " role_detail = ma_foo_answer\n",
1196 | "\n",
1197 | " # 然后用non_struct_answer 生成出detailed的json\n",
1198 | " # json_answer = json.loads(attr_foo_answer)\n",
1199 | "\n",
1200 | " if name == \"李鲁鲁\":\n",
1201 | " json_answer = json.loads(attr_lilulu)\n",
1202 | " elif name == \"冷子昂\":\n",
1203 | " json_answer = json.loads(attr_lengziang)\n",
1204 | " else:\n",
1205 | " role_detail = generate_detailed_description(name, desc)\n",
1206 | " json_str = generate_attr_json( name, desc, role_detail )\n",
1207 | " json_answer = robust_parsing( json_str )\n",
1208 | "\n",
1209 | " # 这里照理说还要经过格式检查,如果格式检查不通过,就随便编一些功法\n",
1210 | "\n",
1211 | " # 对于玩家的3个属性,sum要归一化到30,最大值不超过20\n",
1212 | "\n",
1213 | " json_answer_str = json.dumps(json_answer, ensure_ascii=False)\n",
1214 | "\n",
1215 | " # 根据生成的json 生成一行文字放到chatbot里\n",
1216 | "\n",
1217 | " skill_desc = get_skill_str_short(json_answer)\n",
1218 | "\n",
1219 | " display_board.append((\"生成人物\" + json_answer[\"name\"] + \"\\n\" + skill_desc, None))\n",
1220 | "\n",
1221 | " return role_detail, json_answer_str, get_attr_str_short(json_answer), skill_desc ,display_board, status\n",
1222 | "\n",
1223 | "\n",
1224 | "def generate_madetail(player_attribute,display_board):\n",
1225 | "\n",
1226 | " if player_attribute.strip()==\"\":\n",
1227 | " return \"\", display_board, \"需要生成武功名称,再生成描述。或者直接随机召唤角色\"\n",
1228 | "\n",
1229 | " status = \"确认两个角色都生成之后,可以进入战斗\"\n",
1230 | "\n",
1231 | " json_answer = json.loads( player_attribute )\n",
1232 | "\n",
1233 | " generate_flag = False\n",
1234 | "\n",
1235 | " ans = skill_foo_desc\n",
1236 | " if json_answer[\"name\"] == \"李鲁鲁\":\n",
1237 | " ans = skill_lilulu\n",
1238 | " elif json_answer[\"name\"] == \"冷子昂\":\n",
1239 | " ans = skill_lengziang\n",
1240 | " else:\n",
1241 | " ans = generate_skill_jsonl(json_answer)\n",
1242 | " generate_flag = True\n",
1243 | "\n",
1244 | " # 根据两组功法的名字,生成功法的细节描述\n",
1245 | "\n",
1246 | " # 生成完要做格式检查,如果格式检查不通过,就随便搞一些描述\n",
1247 | "\n",
1248 | " display_board.append((\"为\" + json_answer[\"name\"] + \"生成详细的功法描述\\n\", None))\n",
1249 | "\n",
1250 | " if generate_flag:\n",
1251 | " #save\n",
1252 | " player = Player(json_answer, ans )\n",
1253 | "\n",
1254 | " unique_name = get_unique_from_json(json_answer[\"name\"], json_answer)\n",
1255 | "\n",
1256 | "\n",
1257 | " if len(player.skills)>1 and unique_name != None:\n",
1258 | " add_fighter(player_attribute,ans)\n",
1259 | " display_board.append((\"将新角色\" + json_answer[\"name\"] + \"录入到数据库\\n\", None))\n",
1260 | "\n",
1261 | "\n",
1262 | "\n",
1263 | " return ans,display_board, status\n",
1264 | "\n",
1265 | "def continue_fight(detailed_attr_player1,detailed_attr_player2, detailed_skill_player1,detailed_skill_player2, display_board):\n",
1266 | "\n",
1267 | " if detailed_attr_player1.strip() == \"\" or detailed_attr_player2.strip() == \"\" or detailed_skill_player1.strip() == \"\" or detailed_skill_player2.strip() == \"\":\n",
1268 | " str1 = \"\"\n",
1269 | " if detailed_attr_player1.strip() != \"\":\n",
1270 | " str1 = get_attr_str_short( json.loads(detailed_attr_player1) )\n",
1271 | " str2 = \"\"\n",
1272 | " if detailed_attr_player2.strip() != \"\":\n",
1273 | " str2 = get_attr_str_short( json.loads(detailed_attr_player2) )\n",
1274 | " return detailed_attr_player1, detailed_attr_player2, display_board, str1 , str2 , \"请重新检查人物的生成情况\"\n",
1275 | "\n",
1276 | " json1 = json.loads(detailed_attr_player1)\n",
1277 | " json2 = json.loads(detailed_attr_player2)\n",
1278 | " name1 = json1[\"name\"]\n",
1279 | " name2 = json2[\"name\"]\n",
1280 | "\n",
1281 | " status = f\"\"\"{ name1 } 大战 { name2 }\"\"\"\n",
1282 | "\n",
1283 | " if \"hp\" in json1 and \"hp\" in json2:\n",
1284 | " if json1[\"hp\"] <= 0 and json1[\"hp\"] < json2[\"hp\"]:\n",
1285 | " unique1 = get_unique_from_json(name1, json1)\n",
1286 | " unique2 = get_unique_from_json(name2, json2)\n",
1287 | " # update_elo(unique2, unique1)\n",
1288 | " return detailed_attr_player1, detailed_attr_player2, display_board, \"\" , \"\" , \"战斗结束!请清除战斗或者重新生成人物\"\n",
1289 | "\n",
1290 | " if json2[\"hp\"] <= 0 and json2[\"hp\"] < json1[\"hp\"]:\n",
1291 | " unique1 = get_unique_from_json(name1, json1)\n",
1292 | " unique2 = get_unique_from_json(name2, json2)\n",
1293 | " # update_elo(unique1, unique2)\n",
1294 | " return detailed_attr_player1, detailed_attr_player2, display_board, \"\" , \"\" , \"战斗结束!请清除战斗或者重新生成人物\"\n",
1295 | "\n",
1296 | "\n",
1297 | " game_manager = GameManager(json1, json2, detailed_skill_player1,detailed_skill_player2)\n",
1298 | " msgs, new_player1, new_player2 = game_manager.run()\n",
1299 | " for msg in msgs:\n",
1300 | " display_board.append( msg )\n",
1301 | "\n",
1302 | " if game_manager.flag == \"player1_win\":\n",
1303 | " unique1 = get_unique_from_json(name1, json1)\n",
1304 | " unique2 = get_unique_from_json(name2, json2)\n",
1305 | " update_elo(unique1, unique2)\n",
1306 | " elif game_manager.flag == \"player2_win\":\n",
1307 | " unique1 = get_unique_from_json(name1, json1)\n",
1308 | " unique2 = get_unique_from_json(name2, json2)\n",
1309 | " update_elo(unique2, unique1)\n",
1310 | "\n",
1311 | " new_player1_str = json.dumps(new_player1, ensure_ascii=False)\n",
1312 | " new_player2_str = json.dumps(new_player2, ensure_ascii=False)\n",
1313 | "\n",
1314 | " return new_player1_str, new_player2_str, display_board, get_attr_str_short(new_player1), get_attr_str_short(new_player2), status\n",
1315 | "\n",
1316 | "\n",
1317 | "def callback_random_role(display_board):\n",
1318 | " data = get_random_fighter()\n",
1319 | " name = data[\"name\"]\n",
1320 | " json_str = data[\"attr_str\"]\n",
1321 | " skills_jsonl = data[\"skills\"]\n",
1322 | " json_answer = json.loads(json_str)\n",
1323 | " display_board.append((\"从数据库选择角色\"+name,None))\n",
1324 | " return name, json_str, skills_jsonl, get_attr_str_short(json_answer), get_skill_str_short(json_answer), display_board\n",
1325 | "\n",
1326 | "def callback_role_from_name(display_board, name):\n",
1327 | " data = searching_fighter( name )\n",
1328 | " json_str = data[\"attr_str\"]\n",
1329 | " skills_jsonl = data[\"skills\"]\n",
1330 | " json_answer = json.loads(json_str)\n",
1331 | " display_board.append((\"从数据库选择角色\"+name,None))\n",
1332 | " return name, json_str, skills_jsonl, get_attr_str_short(json_answer), get_skill_str_short(json_answer), display_board\n",
1333 | "\n",
1334 | "def callback_clean_fight(display_board,detailed_attr_player1,detailed_attr_player2):\n",
1335 | " display_board = []\n",
1336 | " json1 = json.loads(detailed_attr_player1)\n",
1337 | " json2 = json.loads(detailed_attr_player2)\n",
1338 | " if \"hp\" in json1:\n",
1339 | " del json1[\"hp\"]\n",
1340 | " if \"hp\" in json2:\n",
1341 | " del json2[\"hp\"]\n",
1342 | "\n",
1343 | " new_detailed_attr_player1 = json.dumps(json1, ensure_ascii=False)\n",
1344 | " new_detailed_attr_player2 = json.dumps(json2, ensure_ascii=False)\n",
1345 | "\n",
1346 | " return display_board,new_detailed_attr_player1,new_detailed_attr_player2\n",
1347 | "\n",
1348 | "def callback_refresh_rank():\n",
1349 | " return get_rank_str()\n",
1350 | "\n"
1351 | ]
1352 | },
1353 | {
1354 | "cell_type": "code",
1355 | "source": [
1356 | "with gr.Blocks() as demo:\n",
1357 | " gr.Markdown(\n",
1358 | " \"\"\"\n",
1359 | " # LuotuoFighter\n",
1360 | "\n",
1361 | " ## 骆驼大乱斗\n",
1362 | "\n",
1363 | " Implemented by 李鲁鲁\n",
1364 | "\n",
1365 | " 项目链接 https://github.com/LC1332/Chat-Haruhi-Suzumiya\n",
1366 | "\n",
1367 | " 这个原型是为了百川Hackathon而初步建立\n",
1368 | "\n",
1369 | " 三种角色建立方式: 根据姓名召唤、随机召唤,或者输入姓名和描述后生成新的人物\n",
1370 | " 姓名召唤会召唤同名人物中战力最强的那个\n",
1371 | " 由于Gradio特性,建立角色要花个几十秒,先点击生成功法,再点击生成功法描述\n",
1372 | " \"\"\"\n",
1373 | " )\n",
1374 | "\n",
1375 | " with gr.Row():\n",
1376 | " with gr.Column():\n",
1377 | " current_status = gr.Textbox(label = \"当前状态\", value=\"请输入角色1的姓名之后生成功法,或进行召唤\")\n",
1378 | "\n",
1379 | " display_board = gr.Chatbot(height = 800)\n",
1380 | "\n",
1381 | " submit_fight2 = gr.Button(\"继续战斗!\")\n",
1382 | " clean_fight = gr.Button(\"清空战斗\")\n",
1383 | "\n",
1384 | "\n",
1385 | " with gr.Column():\n",
1386 | "\n",
1387 | " with gr.Row():\n",
1388 | " name_player1 = gr.Textbox(label=\"角色1姓名\", scale=1, interactive = True, value = \"李鲁鲁\")\n",
1389 | " desc_player1 = gr.Textbox(label=\"角色1描述\", scale=20, value = \"师从,主修剑法\", interactive = True)\n",
1390 | "\n",
1391 | " with gr.Row():\n",
1392 | " generate_ma_player1 = gr.Button(\"生成功法\")\n",
1393 | " generate_madetail_player1 = gr.Button(\"生成功法描述\")\n",
1394 | "\n",
1395 | " with gr.Row():\n",
1396 | " random_sel_player1 = gr.Button(\"随机召唤\")\n",
1397 | " call_player1_with_name1 = gr.Button(\"根据姓名召唤\")\n",
1398 | "\n",
1399 | "\n",
1400 | " with gr.Row():\n",
1401 | " name_player2 = gr.Textbox(label=\"角色2姓名\", scale=1, interactive = True, value = \"冷子昂\")\n",
1402 | " desc_player2 = gr.Textbox(label=\"角色2描述\", scale=20, value = \"师从,主修剑法\", interactive = True)\n",
1403 | " with gr.Row():\n",
1404 | " generate_ma_player2 = gr.Button(\"生成功法\")\n",
1405 | " generate_madetail_player2 = gr.Button(\"生成功法描述\")\n",
1406 | "\n",
1407 | " with gr.Row():\n",
1408 | " random_sel_player2 = gr.Button(\"随机召唤2\")\n",
1409 | " call_player1_with_name2 = gr.Button(\"根据姓名召唤2\")\n",
1410 | "\n",
1411 | " with gr.Row():\n",
1412 | " submit_fight = gr.Button(\"继续战斗!\")\n",
1413 | "\n",
1414 | " with gr.Row():\n",
1415 | " attr_player1 = gr.TextArea(label = \"角色1属性\")\n",
1416 | " skill_player1 = gr.TextArea(label = \"角色1功法描述\")\n",
1417 | "\n",
1418 | " with gr.Row():\n",
1419 | " attr_player2 = gr.TextArea(label = \"角色2属性\")\n",
1420 | " skill_player2 = gr.TextArea(label = \"角色2功法描述\")\n",
1421 | "\n",
1422 | " with gr.Row():\n",
1423 | " refresh_rank = gr.Button(\"刷新天梯\")\n",
1424 | "\n",
1425 | " with gr.Row():\n",
1426 | " rank_showboard = gr.TextArea(label = \"天梯\")\n",
1427 | "\n",
1428 | " with gr.Row():\n",
1429 | " with gr.Column():\n",
1430 | " detailed_description_player1 = gr.TextArea(label = \"角色1具体描述\")\n",
1431 | " detailed_skill_player1 = gr.TextArea(label = \"角色1技能json\")\n",
1432 | " detailed_attr_player1 = gr.TextArea(label = \"角色1属性json\")\n",
1433 | "\n",
1434 | " with gr.Column():\n",
1435 | " detailed_description_player2 = gr.TextArea(label = \"角色2具体描述\")\n",
1436 | " detailed_skill_player2 = gr.TextArea(label = \"角色2技能json\")\n",
1437 | " detailed_attr_player2 = gr.TextArea(label = \"角色2属性json\")\n",
1438 | "\n",
1439 | " generate_ma_player1.click( fn = generate_ma, inputs = [name_player1, desc_player1,display_board], outputs = [detailed_description_player1,detailed_attr_player1,attr_player1,skill_player1,display_board,current_status])\n",
1440 | " generate_ma_player2.click( fn = generate_ma, inputs = [name_player2, desc_player2,display_board], outputs = [detailed_description_player2,detailed_attr_player2,attr_player2,skill_player2,display_board,current_status])\n",
1441 | " generate_madetail_player1.click( fn = generate_madetail, inputs = [detailed_attr_player1,display_board], outputs = [detailed_skill_player1,display_board,current_status])\n",
1442 | " generate_madetail_player2.click( fn = generate_madetail, inputs = [detailed_attr_player2,display_board], outputs = [detailed_skill_player2,display_board,current_status])\n",
1443 | "\n",
1444 | " random_sel_player1.click( fn = callback_random_role, inputs = [display_board], outputs = [name_player1, detailed_attr_player1, detailed_skill_player1, attr_player1, skill_player1, display_board])\n",
1445 | " random_sel_player2.click( fn = callback_random_role, inputs = [display_board], outputs = [name_player2, detailed_attr_player2, detailed_skill_player2, attr_player2, skill_player2, display_board])\n",
1446 | "\n",
1447 | " call_player1_with_name1.click( fn = callback_role_from_name, inputs = [display_board,name_player1], outputs = [name_player1, detailed_attr_player1, detailed_skill_player1, attr_player1, skill_player1, display_board])\n",
1448 | " call_player1_with_name2.click( fn = callback_role_from_name, inputs = [display_board,name_player2], outputs = [name_player2, detailed_attr_player2, detailed_skill_player2, attr_player2, skill_player2, display_board])\n",
1449 | "\n",
1450 | " refresh_rank.click( fn = callback_refresh_rank, inputs = [], outputs = [rank_showboard])\n",
1451 | "\n",
1452 | " clean_fight.click( fn = callback_clean_fight, inputs = [display_board,detailed_attr_player1,detailed_attr_player2], \\\n",
1453 | " outputs = [display_board,detailed_attr_player1,detailed_attr_player2])\n",
1454 | "\n",
1455 | " # callback_role_from_name\n",
1456 | "\n",
1457 | " submit_fight.click( fn = continue_fight, \\\n",
1458 | " inputs = [detailed_attr_player1,detailed_attr_player2, detailed_skill_player1,detailed_skill_player2, display_board],\\\n",
1459 | " outputs = [detailed_attr_player1,detailed_attr_player2, display_board,attr_player1,attr_player2, current_status])\n",
1460 | "\n",
1461 | " submit_fight2.click( fn = continue_fight, \\\n",
1462 | " inputs = [detailed_attr_player1,detailed_attr_player2, detailed_skill_player1,detailed_skill_player2, display_board],\\\n",
1463 | " outputs = [detailed_attr_player1,detailed_attr_player2, display_board,attr_player1,attr_player2, current_status])\n",
1464 | "\n",
1465 | "\n",
1466 | "# demo.launch(debug=False, share = True)\n",
1467 | "demo.launch(debug=True, share = True)\n",
1468 | "\n",
1469 | "# demo.launch(debug=False, share = True)"
1470 | ],
1471 | "metadata": {
1472 | "id": "kyX2ZK0RSXKJ",
1473 | "colab": {
1474 | "base_uri": "https://localhost:8080/",
1475 | "height": 610
1476 | },
1477 | "outputId": "8cc198b1-1ff0-42ae-e7df-c43424cfea42"
1478 | },
1479 | "execution_count": null,
1480 | "outputs": [
1481 | {
1482 | "metadata": {
1483 | "tags": null
1484 | },
1485 | "name": "stdout",
1486 | "output_type": "stream",
1487 | "text": [
1488 | "Colab notebook detected. This cell will run indefinitely so that you can see errors and logs. To turn off, set debug=False in launch().\n",
1489 | "Running on public URL: https://e0b896c14858396383.gradio.live\n",
1490 | "\n",
1491 | "This share link expires in 72 hours. For free permanent hosting and GPU upgrades, run `gradio deploy` from Terminal to deploy to Spaces (https://huggingface.co/spaces)\n"
1492 | ]
1493 | },
1494 | {
1495 | "data": {
1496 | "text/html": [
1497 | ""
1498 | ],
1499 | "text/plain": [
1500 | ""
1501 | ]
1502 | },
1503 | "metadata": {},
1504 | "output_type": "display_data"
1505 | }
1506 | ]
1507 | },
1508 | {
1509 | "cell_type": "code",
1510 | "source": [
1511 | "import pandas as pd\n",
1512 | "edge_data = pd.read_csv(\"edge_data_2.txt\", sep=\"|\")\n",
1513 | "node_data = pd.read_csv(\"node_data_2.txt\", sep=\"|\")\n",
1514 | "print(edge_data)\n",
1515 | "print(node_data)"
1516 | ],
1517 | "metadata": {
1518 | "colab": {
1519 | "base_uri": "https://localhost:8080/"
1520 | },
1521 | "id": "ECUO7z_gKOBA",
1522 | "outputId": "2d1b94cc-61e6-4f06-b9b7-eb0c1e4ef594"
1523 | },
1524 | "execution_count": null,
1525 | "outputs": [
1526 | {
1527 | "output_type": "stream",
1528 | "name": "stdout",
1529 | "text": [
1530 | " Source Target Events Transition\n",
1531 | "0 1 2 英灵殿->北方之路 选择北方之路,与北方怪兽作战\n",
1532 | "1 1 3 英灵殿->黑暗森林之路 (挑战)选择黑暗森林之路,面对隐匿的黑暗生物\n",
1533 | "2 2 4 北方之路->冰原巨人 通过北方之路,遇到冰原巨人\n",
1534 | "3 3 4 黑暗森林之路->冰原巨人 通过黑暗森林,也来到了冰原巨人面前 \n",
1535 | "4 4 5 冰原巨人->黑暗精灵 打败冰原巨人,遇到速度极快的黑暗精灵\n",
1536 | "5 4 6 冰原巨人->恶龙法夫纳 (挑战)打败冰原巨人,有资格挑战恶龙法夫纳\n",
1537 | "6 5 7 黑暗精灵->山地巨人 通过黑暗精灵的挑战,迎来山地巨人\n",
1538 | "7 6 7 恶龙法夫纳->山地巨人 通过恶龙的挑战,遇上山地巨人\n",
1539 | "8 7 8 山地巨人->北地冰原巨熊 打败山地巨人,遭遇北地冰原巨熊 \n",
1540 | "9 7 9 山地巨人->海姆冥界使者 (挑战)打败山地巨人,有资格挑战海姆冥界使者\n",
1541 | "10 8 10 北地冰原巨熊->最后试炼 通过北地冰原巨熊,来到最后试炼\n",
1542 | "11 9 10 海姆冥界使者->最后试炼 通过海姆冥界使者,来到最后试炼\n",
1543 | " 序号 事件名 敌人战斗力 奖励 描述\n",
1544 | "0 1 踏上英灵殿 0 - 你来到英灵殿,开始了成为英雄的旅程\n",
1545 | "1 2 北方食人妖 15 str+1 北方食人妖芬尼尔持有神秘战斧,如果打败它,你的力量将得到提升\n",
1546 | "2 3 挑战巨龙法夫纳 20 str+3 恶龙法夫纳拥有无穷力量,如果你能打败它,你的力量将大幅提升\n",
1547 | "3 4 冰原巨人 16 - 冰原巨人体型巨大,这场战斗对你很艰难\n",
1548 | "4 5 黑暗精灵 17 spd+1 黑暗精灵速度极快,击败它可以提高你的敏捷\n",
1549 | "5 6 海姆冥界使者 21 spd+3 海姆冥界使者将考验你的反应能力,如果成功击败,你的敏捷将大幅提升 \n",
1550 | "6 7 山地巨人 18 - 山地巨人力大无穷,这场战斗消耗你大量体力\n",
1551 | "7 8 北地冰原巨熊 19 vit+1 北地冰原巨熊体质惊人,打败它可以增强你的生命力\n",
1552 | "8 9 神圣武士泰尔 21 vit+3 神圣武士泰尔拥有神力,如果你能战胜他,你的生命力将大幅提升\n",
1553 | "9 10 最后的试炼 25 - 这是成为英雄的最后试炼,只有打败25战力的对手才能通过\n"
1554 | ]
1555 | }
1556 | ]
1557 | },
1558 | {
1559 | "cell_type": "code",
1560 | "execution_count": 65,
1561 | "metadata": {
1562 | "id": "eRnOOHiswDrz",
1563 | "colab": {
1564 | "base_uri": "https://localhost:8080/"
1565 | },
1566 | "outputId": "83b7d75f-d5ad-46fb-8bb6-dee16aa773b8"
1567 | },
1568 | "outputs": [
1569 | {
1570 | "output_type": "stream",
1571 | "name": "stdout",
1572 | "text": [
1573 | "勇者,请报上名来!米唯实\n",
1574 | "何门何派!\n",
1575 | "示例:李鲁鲁 山东逍遥派的游戏角色,擅长人工智能傀儡术\n",
1576 | "擅长飞刀\n",
1577 | "正在生成初始角色\n",
1578 | "请为角色进一步生成详细功法\n",
1579 | "生成人物米唯实\n",
1580 | "飞刀绝技:\n",
1581 | "破云斩-云破斩-风雷破-刀光破碎-破空刀影-\n",
1582 | "幻影刀:\n",
1583 | "幻影刀雨-迷踪刀影-幻影斩-刀光迷离-\n",
1584 | " 防御:飞行身法\n",
1585 | "确认两个角色都生成之后,可以进入战斗\n",
1586 | "为米唯实生成详细的功法描述\n",
1587 | "\n",
1588 | "将新角色米唯实录入到数据库\n",
1589 | "\n"
1590 | ]
1591 | }
1592 | ],
1593 | "source": [
1594 | "import pandas as pd\n",
1595 | "\n",
1596 | "class User:\n",
1597 | " def __init__(self):\n",
1598 | " self.name = None\n",
1599 | " self.description = None #\n",
1600 | " self.skill_user = None #功法描述\n",
1601 | " self.attr_user = None #属性\n",
1602 | " self.node = 1 #位置\n",
1603 | " self.detailed_attr_user = None #属性json\n",
1604 | " self.detailed_skill_user = None #技能json\n",
1605 | "\n",
1606 | "user = User()\n",
1607 | "user.name = input(\"勇者,请报上名来!\")\n",
1608 | "user.description = input(\"何门何派!\\n示例:李鲁鲁 山东逍遥派的游戏角色,擅长人工智能傀儡术\\n\")\n",
1609 | "print(\"正在生成初始角色\")\n",
1610 | "_,user.detailed_attr_user,user.attr_user,user.skill_user,display_board,current_status = generate_ma(user.name, user.description, [])\n",
1611 | "print(current_status)\n",
1612 | "for text in display_board:\n",
1613 | " if text[0]:\n",
1614 | " print(text[0])\n",
1615 | " elif text[1]:\n",
1616 | " print(text[1])\n",
1617 | "user.detailed_skill_user,display_board,current_status = generate_madetail(user.detailed_attr_user, [])\n",
1618 | "print(current_status)\n",
1619 | "for text in display_board:\n",
1620 | " if text[0]:\n",
1621 | " print(text[0])\n",
1622 | " elif text[1]:\n",
1623 | " print(text[1])\n",
1624 | "\n",
1625 | "edge_data = pd.read_csv(\"edge_data_2.txt\", sep=\"|\")\n",
1626 | "node_data = pd.read_csv(\"node_data_2.txt\", sep=\"|\")\n",
1627 | "# print(edge_data)\n",
1628 | "# print(node_data)\n",
1629 | "\n",
1630 | "class Enemy:\n",
1631 | " def __init__(self):\n",
1632 | " self.name = None\n",
1633 | " self.description = None #\n",
1634 | " self.skill_enemy = None #功法描述\n",
1635 | " self.attr_enemy = None #属性\n",
1636 | " self.node = 1 #位置\n",
1637 | " self.detailed_attr_enemy = None #属性json\n",
1638 | " self.detailed_skill_enemy = None #技能json\n"
1639 | ]
1640 | },
1641 | {
1642 | "cell_type": "code",
1643 | "source": [
1644 | "def node_process(user):\n",
1645 | " node = user.node\n",
1646 | " node_desc = node_data[node_data['序号'] == node]['描述'].values[0]\n",
1647 | " print(node_desc)\n",
1648 | " find_flag = False\n",
1649 | " name_node = node_data[node_data['序号'] == node]['事件名'].values[0]\n",
1650 | " global fighter_data\n",
1651 | " for data in fighter_data:\n",
1652 | " if data[\"name\"] == name_node:\n",
1653 | " find_flag = True\n",
1654 | " break\n",
1655 | " if find_flag == False:\n",
1656 | " return\n",
1657 | " else:\n",
1658 | " enemy = Enemy()\n",
1659 | " enemy.name, enemy.detailed_attr_enemy, enemy.detailed_skill_enemy, enemy.attr_enemy, enemy.skill_enemy, display_board = callback_role_from_name([], name_node)\n",
1660 | " while True:\n",
1661 | " user.detailed_attr_user,enemy.detailed_attr_enemy, display_board , user.attr_user, enemy.attr_enemy, current_status = continue_fight(user.detailed_attr_user, enemy.detailed_attr_enemy, user.detailed_skill_user, enemy.detailed_skill_enemy, [])\n",
1662 | " # print(display_board)\n",
1663 | " for text in display_board:\n",
1664 | " if text[0]:\n",
1665 | " print(text[0])\n",
1666 | " elif text[1]:\n",
1667 | " print(text[1])\n",
1668 | " print(current_status)\n",
1669 | " if input(\"任意键以继续\") == \"q\":\n",
1670 | " user_attr = json.loads(user.detailed_attr_user)\n",
1671 | " print(\"您的血量剩余\" + str(user_attr[\"hp\"]) + \"\\n下一轮战斗前我们将自动为您补满\")\n",
1672 | " user_attr[\"hp\"] = (user_attr[\"VIT\"] + 10) * 30\n",
1673 | " user.detailed_attr_user = json.dumps(user_attr)\n",
1674 | " break\n",
1675 | "\n",
1676 | "def update_player(user):\n",
1677 | " rewards = node_data[node_data['序号'] == user.node]['奖励'].values[0]\n",
1678 | " rewards = rewards.replace(\"str\", \"力量\")\n",
1679 | " rewards = rewards.replace(\"vit\", \"体质\")\n",
1680 | " rewards = rewards.replace(\"spd\", \"速度\")\n",
1681 | " attr_list = user.attr_user.split(\"\\n\")\n",
1682 | " if rewards is not None:\n",
1683 | " for reward in rewards.split(','):\n",
1684 | " if '+' in reward:\n",
1685 | " for attr in attr_list:\n",
1686 | " key, value = attr.split(\":\")\n",
1687 | " if key in rewards:\n",
1688 | " new_value = str(int(value) + int(rewards.split(\"+\")[1]))\n",
1689 | " user.attr_user = user.attr_user.replace(attr, f\"{key}:{new_value}\")\n",
1690 | "\n",
1691 | "while True:\n",
1692 | " node_process(user)\n",
1693 | " update_player(user)\n",
1694 | " # user_attr = json.loads(user.detailed_attr_user)\n",
1695 | " print(\"您目前的属性:\")\n",
1696 | " print(user.attr_user)\n",
1697 | " # user_attr[\"hp\"] = (user_attr[\"VIT\"] + 10) * 30\n",
1698 | " edges = edge_data[edge_data['Source'] == user.node]\n",
1699 | " if edges.empty:\n",
1700 | " print(\"游戏结束!\")\n",
1701 | " break\n",
1702 | "\n",
1703 | " option = 1\n",
1704 | "\n",
1705 | " for i, edge in edges.iterrows():\n",
1706 | " target = edge['Target']\n",
1707 | " print(f\"{option}. {edge['Events']}\")\n",
1708 | " print(\" \" + edge['Transition'])\n",
1709 | " option += 1\n",
1710 | "\n",
1711 | " choice = int(input(\"请选择:\"))\n",
1712 | " user.node = edges.iloc[choice-1]['Target']\n",
1713 | "print(\"你的最终属性:\")\n",
1714 | "print(user.attr_user)"
1715 | ],
1716 | "metadata": {
1717 | "colab": {
1718 | "base_uri": "https://localhost:8080/",
1719 | "height": 1000
1720 | },
1721 | "id": "OcxyBx9KyF5h",
1722 | "outputId": "9973c7f1-9b00-4968-d462-bca7e7dafb02"
1723 | },
1724 | "execution_count": 67,
1725 | "outputs": [
1726 | {
1727 | "output_type": "stream",
1728 | "name": "stdout",
1729 | "text": [
1730 | "恶龙法夫纳拥有无穷力量,如果你能打败它,你的力量将大幅提升\n",
1731 | "您目前的属性:\n",
1732 | "力量:21\n",
1733 | "体质:10\n",
1734 | "速度:18\n",
1735 | "1. 黑暗森林之路->冰原巨人\n",
1736 | " 通过黑暗森林,也来到了冰原巨人面前 \n",
1737 | "冰原巨人体型巨大,这场战斗对你很艰难\n",
1738 | "米唯实手中刀光闪烁,如雨点般倾泻而下,一招“幻影刀雨”,刀影交错,密不透风造成了60的伤害。\n",
1739 | "冰原巨人身法灵动,双手凝结冰霜之力,一招“冰封天地”,寒气弥漫,冰雪覆盖整个战场,将米唯实困于其中造成了79的伤害。\n",
1740 | "米唯实 大战 冰原巨人\n",
1741 | "米唯实手中飞刀闪烁不定,刀光如电,一招“刀光破碎”,刀影交错,将冰原巨人四面八方都笼罩其中造成了60的伤害。\n",
1742 | "冰原巨人仰天发出一声震天怒吼,声波如潮水般向四周扩散,敌人无不心生恐惧造成了79的伤害。\n",
1743 | "米唯实 大战 冰原巨人\n",
1744 | "米唯实身形如鬼魅般闪动,手中刀光幻化出无数刀影,一招“迷踪刀影”,刀光瞬间覆盖冰原巨人周身造成了60的伤害。\n",
1745 | "冰原巨人手中寒光闪动,一招“冰崩斩”,剑势如山崩,寒气凛冽,犹如冰山崩塌般猛烈地斩向米唯实造成了79的伤害。\n",
1746 | "米唯实 大战 冰原巨人\n",
1747 | "米唯实手中刀光闪烁,如雨点般倾泻而下,一招“幻影刀雨”,刀影交错,密不透风造成了60的伤害。\n",
1748 | "冰原巨人手中寒光闪动,一招“冰崩斩”,剑势如山崩,寒气凛冽,犹如冰山崩塌般猛烈地斩向米唯实造成了79的伤害。\n",
1749 | "米唯实 大战 冰原巨人\n",
1750 | "米唯实手中飞刀闪烁不定,刀光如电,一招“刀光破碎”,刀影交错,将冰原巨人四面八方都笼罩其中造成了60的伤害。\n",
1751 | "冰原巨人仰天发出一声震天怒吼,声波如潮水般向四周扩散,敌人无不心生恐惧造成了79的伤害。\n",
1752 | "米唯实 大战 冰原巨人\n",
1753 | "米唯实手中刀光闪烁,如雨点般倾泻而下,一招“幻影刀雨”,刀影交错,密不透风造成了60的伤害。\n",
1754 | "冰原巨人身法灵动,双手凝结冰霜之力,一招“冰封天地”,寒气弥漫,冰雪覆盖整个战场,将米唯实困于其中造成了79的伤害。\n",
1755 | "米唯实 大战 冰原巨人\n",
1756 | "冰原巨人_100_120 wins 米唯实_90_80\n",
1757 | "米唯实手中刀光一闪,刹那间幻化出无数刀影,一招“幻影斩”,刀光交错中直奔冰原巨人而去造成了60的伤害。\n",
1758 | "冰原巨人怒然跃起,双脚狠狠地踏向地面,一招“狂怒踏地”,地动山摇,尘土飞扬造成了79的伤害。\n",
1759 | "米唯实战败了\n",
1760 | "米唯实 大战 冰原巨人\n",
1761 | "战斗结束!请清除战斗或者重新生成人物\n",
1762 | "您的血量剩余-41.54075646110552\n",
1763 | "下一轮战斗前我们将自动为您补满\n",
1764 | "您目前的属性:\n",
1765 | "\n",
1766 | "1. 冰原巨人->黑暗精灵\n",
1767 | " 打败冰原巨人,遇到速度极快的黑暗精灵\n",
1768 | "2. 冰原巨人->恶龙法夫纳\n",
1769 | " (挑战)打败冰原巨人,有资格挑战恶龙法夫纳\n",
1770 | "海姆冥界使者将考验你的反应能力,如果成功击败,你的敏捷将大幅提升 \n",
1771 | "米唯实身形一闪,手中飞刀化作一道云霞,迅猛无比地斩向海姆冥界使者,正是一招“云破斩”造成了67的伤害。\n",
1772 | "海姆冥界使者身形如幽影般闪动,手中剑光闪烁,施展出一招“幽影斩”,剑光如电,直刺米唯实要害造成了67的伤害。\n",
1773 | "米唯实 大战 海姆冥界使者\n",
1774 | "任意键以继续\n",
1775 | "米唯实身形如鬼魅般闪动,手中刀光幻化出无数刀影,一招“迷踪刀影”,刀光瞬间覆盖海姆冥界使者周身造成了67的伤害。\n",
1776 | "海姆冥界使者双掌聚集黑暗之力,一招“冥焰爆破”,瞬间爆发出炽热的黑暗火焰,向米唯实喷涌而出造成了67的伤害。\n",
1777 | "米唯实 大战 海姆冥界使者\n"
1778 | ]
1779 | },
1780 | {
1781 | "output_type": "error",
1782 | "ename": "KeyboardInterrupt",
1783 | "evalue": "ignored",
1784 | "traceback": [
1785 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
1786 | "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)",
1787 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 47\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 48\u001b[0m \u001b[0;32mwhile\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 49\u001b[0;31m \u001b[0mnode_process\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0muser\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 50\u001b[0m \u001b[0mupdate_player\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0muser\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 51\u001b[0m \u001b[0;31m# user_attr = json.loads(user.detailed_attr_user)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
1788 | "\u001b[0;32m\u001b[0m in \u001b[0;36mnode_process\u001b[0;34m(user)\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtext\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 25\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcurrent_status\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 26\u001b[0;31m \u001b[0;32mif\u001b[0m \u001b[0minput\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"任意键以继续\"\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"q\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 27\u001b[0m \u001b[0muser_attr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mjson\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mloads\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0muser\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdetailed_attr_user\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 28\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"您的血量剩余\"\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0muser_attr\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"hp\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m\"\\n下一轮战斗前我们将自动为您补满\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
1789 | "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/ipykernel/kernelbase.py\u001b[0m in \u001b[0;36mraw_input\u001b[0;34m(self, prompt)\u001b[0m\n\u001b[1;32m 849\u001b[0m \u001b[0;34m\"raw_input was called, but this frontend does not support input requests.\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 850\u001b[0m )\n\u001b[0;32m--> 851\u001b[0;31m return self._input_request(str(prompt),\n\u001b[0m\u001b[1;32m 852\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_parent_ident\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 853\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_parent_header\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
1790 | "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/ipykernel/kernelbase.py\u001b[0m in \u001b[0;36m_input_request\u001b[0;34m(self, prompt, ident, parent, password)\u001b[0m\n\u001b[1;32m 893\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyboardInterrupt\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 894\u001b[0m \u001b[0;31m# re-raise KeyboardInterrupt, to truncate traceback\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 895\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mKeyboardInterrupt\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Interrupted by user\"\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 896\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 897\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlog\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwarning\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Invalid Message:\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mexc_info\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
1791 | "\u001b[0;31mKeyboardInterrupt\u001b[0m: Interrupted by user"
1792 | ]
1793 | }
1794 | ]
1795 | }
1796 | ],
1797 | "metadata": {
1798 | "colab": {
1799 | "provenance": []
1800 | },
1801 | "kernelspec": {
1802 | "display_name": "Python 3",
1803 | "name": "python3"
1804 | },
1805 | "language_info": {
1806 | "name": "python"
1807 | }
1808 | },
1809 | "nbformat": 4,
1810 | "nbformat_minor": 0
1811 | }
1812 |
--------------------------------------------------------------------------------
/figures/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/.DS_Store
--------------------------------------------------------------------------------
/figures/BattleExample.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/BattleExample.jpg
--------------------------------------------------------------------------------
/figures/BattleExample.pptx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/BattleExample.pptx
--------------------------------------------------------------------------------
/figures/BattleLogs.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/BattleLogs.jpg
--------------------------------------------------------------------------------
/figures/BattleLogs.pptx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/BattleLogs.pptx
--------------------------------------------------------------------------------
/figures/FeatureList.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/FeatureList.jpg
--------------------------------------------------------------------------------
/figures/FeatureList.pptx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/FeatureList.pptx
--------------------------------------------------------------------------------
/figures/Hit_Damage_Relationship.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/Hit_Damage_Relationship.png
--------------------------------------------------------------------------------
/figures/LifeReloaded.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/LifeReloaded.jpg
--------------------------------------------------------------------------------
/figures/RPG-script_with_image/冰原巨人.pptx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/RPG-script_with_image/冰原巨人.pptx
--------------------------------------------------------------------------------
/figures/RPG-script_with_image/北方食人妖.pptx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/RPG-script_with_image/北方食人妖.pptx
--------------------------------------------------------------------------------
/figures/RPG-script_with_image/山地巨人.pptx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/RPG-script_with_image/山地巨人.pptx
--------------------------------------------------------------------------------
/figures/RPG-script_with_image/神圣武士泰尔.pptx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/RPG-script_with_image/神圣武士泰尔.pptx
--------------------------------------------------------------------------------
/figures/RPG-script_with_image/黑暗精灵.pptx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/RPG-script_with_image/黑暗精灵.pptx
--------------------------------------------------------------------------------
/figures/YingXiong.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/YingXiong.png
--------------------------------------------------------------------------------
/figures/character_earth.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/character_earth.jpeg
--------------------------------------------------------------------------------
/figures/character_fire.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/character_fire.jpeg
--------------------------------------------------------------------------------
/figures/character_water.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/character_water.jpeg
--------------------------------------------------------------------------------
/figures/dmg_per_hp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/dmg_per_hp.png
--------------------------------------------------------------------------------
/figures/level_selection.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/level_selection.jpeg
--------------------------------------------------------------------------------
/figures/xiuxian.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LC1332/Luotuo-Fighter/908febaccc872ad800d0358f200389ed83a393fb/figures/xiuxian.jpeg
--------------------------------------------------------------------------------
|