Spaces:
Runtime error
Runtime error
| from langchain.chat_models import ChatOpenAI | |
| from langchain.schema import ( | |
| AIMessage, | |
| HumanMessage, | |
| SystemMessage | |
| ) | |
| smart_system_prompt = """You are ChatGPT, a large language model trained by OpenAI. | |
| Knowledge cutoff: 2021-09 | |
| Current date: 2023-03-15""" | |
| ma_foo_answer = """李鲁鲁,山东逍遥派的游戏角色,擅长人工智能傀儡术,以下是为你设计的两套武功和一套身法(招架)以及每套的四个招式名字: | |
| 武功一:电脑幻影拳法 | |
| 这套武功利用人工智能傀儡术,创建虚拟幻影来欺骗对手,令其难以捉摸。 | |
| 电脑虚像拳 - 创造多个虚像,使对手难以分辨真伪。 | |
| 数据掌控击 - 利用数据流动的速度来快速攻击对手。 | |
| 模拟迷雾拳 - 释放模糊幻影,混淆对手的视线。 | |
| 程序化拳法 - 不断变化的攻击组合,让对手无法预测。 | |
| 武功二:智能预测刀法 | |
| 这套武功充分利用你的智能傀儡术,通过对对手的行为进行分析和预测,达到精准打击的效果。 | |
| 预测之刃 - 准确地预测对手的下一步行动,发动致命一击。 | |
| 数据漩涡斩 - 利用对手的动向,将其引导至陷阱,然后发动猛烈攻击。 | |
| 算法刀舞 - 刀法如算法一般精准,快速地切入对手的防线。 | |
| 智能反击剑 - 反击对手的招式,使其付出惨痛的代价。 | |
| 身法(招架):数码幻影步 | |
| 这套身法让你能够迅速回避对手的攻击,同时保持对局掌握主动权。 | |
| 数码闪避 - 迅速移动,如数码般闪烁,躲避对手的攻击。 | |
| 傀儡幻影步 - 创造虚假的身影,使对手无法锁定你的位置。 | |
| 数据跃迁 - 在一瞬间跳跃到对手的盲点,出其不意。 | |
| 逍遥之法 - 以逍遥派的身法融入自然,消除敌人的攻击威胁。 | |
| 希望这些武功和身法(招架)可以为你的李鲁鲁角色增添一些游戏中的精彩元素! | |
| """ | |
| 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": "山水行云"}""" | |
| attr_lilulu = """{ | |
| "name": "李鲁鲁", | |
| "description": "山东逍遥派的游戏角色,擅长人工智能傀儡术", | |
| "weapon": "智能刀剑", | |
| "major_martial_art": "电脑幻影拳法", | |
| "major_movements": ["电脑虚像拳", "数据掌控击", "模拟迷雾拳", "程序化拳法"], | |
| "major_damage": 75, | |
| "secondary_martial_art": "智能预测刀法", | |
| "secondary_movements": ["预测之刃", "数据漩涡斩", "算法刀舞", "智能反击剑"], | |
| "secondary_damage": 85, | |
| "footwork_and_body_method": "数码幻影步", | |
| "STR": 6, | |
| "VIT": 5, | |
| "SPD": 18 | |
| } | |
| """ | |
| attr_lengziang = """{ | |
| "name": "冷子昂", | |
| "description": "擅长冰系技能", | |
| "weapon": "冰刃", | |
| "major_martial_art": "冰霜寒刃功", | |
| "major_movements": ["冰刃斩破", "冰风流转", "冰龙穿云", "冰心彻骨"], | |
| "major_damage": 80, | |
| "secondary_martial_art": "冰封无影步", | |
| "secondary_movements": ["冰封幻影", "无影冻结", "冰刃闪耀", "冰封禅定"], | |
| "secondary_damage": 70, | |
| "footwork_and_body_method": "冰心护身法", | |
| "STR": 8, | |
| "VIT": 6, | |
| "SPD": 15 | |
| } | |
| """ | |
| json_str_huangrong = """{ | |
| "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 | |
| }""" | |
| skill_foo_desc = """ | |
| {"招式":"预测之眼","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]四面八方都是傀儡的身影,形势险恶。"} | |
| """ | |
| skill_lilulu = """ | |
| {"招式":"电脑虚像拳","description":"[player]运用电脑幻影拳法,双拳虚虚实实,制造出多个虚像,令[target]难以分辨真伪,招招不离其身。","missing":"[player]运用电脑幻影拳法,双拳虚虚实实,制造出多个虚像,令[target]难以分辨真伪。"} | |
| {"招式":"数据掌控击","description":"[player]施展数据掌控击,利用数据流动的速度,犹如电光闪烁,快速攻击[target],剑招迅猛,如电一般。","missing":"[player]施展数据掌控击,利用数据流动的速度,犹如电光闪烁,快速攻击[target],剑招迅猛。"} | |
| {"招式":"模拟迷雾拳","description":"[player]施展模拟迷雾拳,释放出模糊幻影,混淆[target]的视线,令其难以辨别攻击方向。","missing":"[player]施展模拟迷雾拳,释放出模糊幻影,混淆[target]的视线,令其难以辨别攻击方向。"} | |
| {"招式":"程序化拳法","description":"[player]运用程序化拳法,以不断变化的攻击组合,让[target]难以预测招式,时而快时而慢,攻击变幻莫测。","missing":"[player]运用程序化拳法,以不断变化的攻击组合,让[target]难以预测招式,攻击变幻莫测。"} | |
| {"招式":"预测之刃","description":"[player]使出预测之刃,准确地预测[target]的下一步行动,犹如镜中水月,剑锋准确地击中[target]的要害。","missing":"[player]使出预测之刃,准确地预测[target]的下一步行动,犹如镜中水月,剑锋迅速挥出。"} | |
| {"招式":"数据漩涡斩","description":"[player]施展数据漩涡斩,利用[target]的动向,将其引导至剑刃之下,然后发动猛烈攻击,犹如漩涡将[target]吸入其中。","missing":"[player]施展数据漩涡斩,利用[target]的动向,将其引导至剑刃之下,然后发动猛烈攻击,剑招异常犀利。"} | |
| {"招式":"算法刀舞","description":"[player]挥舞着长剑,使出算法刀舞,刀法如算法一般精准,快速地切入[target]的防线,剑锋连续不断地斩向[target]。","missing":"[player]挥舞着长剑,使出算法刀舞,刀法如算法一般精准,快速地切入[target]的防线,剑招变化多端。"} | |
| {"招式":"智能反击剑","description":"[player]运用智能反击剑,反击[target]的招式,使其付出惨痛的代价,一瞬间的犹豫就足以让[target]受伤。","missing":"[player]运用智能反击剑,反击[target]的招式,使其陷入困境,一瞬间的犹豫足以让[target]付出代价。"} | |
| """ | |
| skill_lengziang = """ | |
| {"招式":"冰刃斩破","description":"[player]聚集冰之力量于剑上,使出冰刃斩破,剑锋犹如寒冰之刃斩向[target]的要害部位,寒气逼人,剑光炽烈。","missing":"[player]聚集冰之力量于剑上,使出冰刃斩破,剑锋犹如寒冰之刃,闪电般挥出。"} | |
| {"招式":"冰风流转","description":"[player]身体如风一般旋转,同时释放出冰风刃,打击周围的敌人,冷飕飕的寒风环绕,[target]身不由己地被吹向一旁。","missing":"[player]身体如风一般旋转,同时释放出冰风刃,冷飕飕的寒风环绕,风刃在[target]周围飞舞。"} | |
| {"招式":"冰龙穿云","description":"[player]召唤出一条冰龙,冰龙穿越云层直扑[target],寒冰之力凝聚在龙爪之上,将[target]冻结一切,一切都难以抵挡。","missing":"[player]召唤出一条冰龙,冰龙穿越云层,龙爪直扑[target],寒冰之力凝聚在龙爪之上,寒意森然。"} | |
| {"招式":"冰心彻骨","description":"[player]凝聚冰之力于手,一触即可让[target]骨骼寒冷,动弹不得,彻底冰封,剑锋轻轻触及[target],寒意透骨。","missing":"[player]凝聚冰之力于手,一触即可让[target]骨骼寒冷,动弹不得,寒气透骨,剑锋轻轻触及[target]。"} | |
| {"招式":"冰封幻影","description":"[player]运用冰封无影步,快速移动,留下一道冰封的幻影,使[target]无法辨别真伪,幻影与实体交替出现,令[target]不知所措。","missing":"[player]运用冰封无影步,快速移动,留下一道冰封的幻影,使[target]无法辨别真伪。"} | |
| {"招式":"无影冻结","description":"[player]以极快的速度接近[target],然后冻结[target]的动作,使其陷入无法自拔的状态,如同身陷冰封之中,动弹不得。","missing":"[player]以极快的速度接近[target],然后冻结[target]的动作,使其陷入无法自拔的状态。"} | |
| {"招式":"冰刃闪耀","description":"[player]利用冰之能量,瞬间闪现至[target]身边,发动迅猛的攻击,剑锋如星光般闪烁,将[target]包围其中。","missing":"[player]利用冰之能量,瞬间闪现至[target]身边,发动迅猛的攻击,剑锋如星光般闪烁。"} | |
| {"招式":"冰封禅定","description":"[player]静心冥想,将身体冰封,使自己无法被[target]察觉,达到不可捉摸的状态,如同融入冰封禅定之中。","missing":"[player]静心冥想,将身体冰封,使自己无法被[target]察觉,达到不可捉摸的状态。"} | |
| """ | |
| skill_huangrong = """ | |
| {"招式": "狗啸山林", "description": "[player]手中长棒一挥,发出一声凄厉的狗啸,棒影如山林般扑向[target]", "missing": "[player]手中长棒一挥,发出一声凄厉的狗啸,棒影如山林般扑向[target]"} | |
| {"招式": "棒影重重", "description": "[player]身形连转,手中长棒化作无数道棒影,重重叠叠地向[target]砸去", "missing": "[player]身形连转,手中长棒化作无数道棒影,重重叠叠地向[target]砸去"} | |
| {"招式": "狗尾续貂", "description": "[player]手中长棒如狗尾续貂般灵动,连续变换方向,向[target]连续攻击", "missing": "[player]手中长棒如狗尾续貂般灵动,连续变换方向,向[target]连续攻击"} | |
| {"招式": "狗急跳墙", "description": "[player]猛地一跃,手中长棒带起狂风,如狗急跳墙般向[target]砸去", "missing": "[player]猛地一跃,手中长棒带起狂风,如狗急跳墙般向[target]砸去"} | |
| {"招式": "落英如雨", "description": "[player]身形一闪,双掌连续拍出,犹如漫天飘落的落英,掌风凌厉,瞬间覆盖[target]周身", "missing": "[player]身形一闪,双掌连续拍出,犹如漫天飘落的落英,掌风凌厉,向[target]周身袭去"} | |
| {"招式": "神剑破空", "description": "[player]手中剑光闪烁,一剑刺出,剑气凌厉无比,犹如神剑破开虚空,直指[target]要害", "missing": "[player]手中剑光闪烁,一剑刺出,剑气凌厉无比,直向[target]要害刺去"} | |
| {"招式": "飞花流水", "description": "[player]身形如飞,双掌连续拍击,掌风如流水般连绵不绝,将[target]团团围住", "missing": "[player]身形如飞,双掌连续拍击,掌风如流水般连绵不绝,向[target]团团包围"} | |
| {"招式": "剑指苍穹", "description": "[player]手中长剑一指,剑光直冲云霄,气势如虹,剑指直指苍穹,威力惊人", "missing": "[player]手中长剑一指,剑光直冲云霄,气势如虹,直指苍穹"} | |
| """ | |
| def generate_detailed_description(name, description): | |
| task_message = f"""我的名字叫“{name}”,假设我是一个武侠中的游戏角色,{description} | |
| 请基于我的名字和门派,先为我设计2套武功和一套身法或者招架。 | |
| 再为每套武功设计4个对应招式的名字。""" | |
| messages = [ | |
| SystemMessage(content=smart_system_prompt), | |
| HumanMessage(content=task_message), | |
| ] | |
| chat = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.3) | |
| response = chat(messages) | |
| return response.content | |
| def generate_attr_json(name, description, detailed_description): | |
| task_message = f"""我正在为我的武侠游戏设计人物。给定一个人物和这个人物的背景描述(可选) | |
| 我希望你根据这个人物的背景和名字以及输入的suggestion信息,为我生成这个人的资料,以json的格式输出,包括 | |
| description: 这个角色的背景等信息 | |
| weapon: 这个人使用的武器种类, | |
| major_martial_art: 这个人的主要武学 | |
| major_movements: 这个人主要武学的4个对应招式的名字。招式的名字需要尽可能和major_martial_art有关。movements的名字尽量不要使用重复的文字。可以使用形象的动作或者是一些动物的比喻。 | |
| major_damage: 主武学的威力,50到150之间的整数。重视速度的功法威力会低一些。重视攻击的功法威力会高一些 | |
| secondary_movements: 这个角色的次要武学 | |
| secondary_movements: 这个人次要武学的4个对应招式的名字。招式的名字需要尽可能和secondary_movements有关 | |
| secondary_damage: 次要武学的威力,50到150之间的整数。 | |
| footwork_and_body_method: 这个角色的轻功或者防御功法 | |
| STR: 角色的攻击力, 0-20之间的整数 | |
| VIT: 角色的体质, 0-20之间的整数 | |
| SPD: 角色的速度,0-20之间的整数 | |
| """ | |
| example_input = """example_input: | |
| name: 令狐冲 | |
| description: - | |
| suggestion:-""" | |
| example_output = """example_output: | |
| { | |
| "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 | |
| }""" | |
| input = f"""input: | |
| name: {name}, | |
| description: {description}, | |
| suggestion: `{detailed_description}` | |
| """ | |
| messages = [ | |
| SystemMessage(content=smart_system_prompt), | |
| HumanMessage(content=task_message), | |
| HumanMessage(content=example_input), | |
| AIMessage(content=example_output), | |
| HumanMessage(content=input)] | |
| chat = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.1) | |
| response = chat(messages) | |
| return response.content | |
| import json | |
| def robust_parsing(input_str): | |
| try: | |
| return json.loads(input_str) | |
| except json.JSONDecodeError: | |
| start = input_str.find('{') | |
| end = input_str.rfind('}') + 1 | |
| if start != -1 and end != -1: | |
| try: | |
| return json.loads(input_str[start:end]) | |
| except json.JSONDecodeError: | |
| pass | |
| return None | |
| def generate_skill_detail(martial_art_name, movements): | |
| task_message = """现在我希望你根据武侠小说中的武功和招式的名字。为招式补全合理的description和missing描述。 | |
| 在description的描述中,player可以击中目标,可以有兵器撞击声响等描述。 | |
| 在missing描述中,player并不一定击中目标,不可以有击落、击中、夺去这样的描述 | |
| 在用[player]代表技能的使用者,用[target]代表技能的目标。结果需用合理的jsonl格式展示,下面是一个例子。""" | |
| example_input = """example input: | |
| martial_art_name = 华山剑法 | |
| {"招式":"百丈飞瀑"} | |
| {"招式":"百鸟朝凤"} | |
| {"招式":"青山隐隐"} | |
| {"招式":"飞沙走石"}""" | |
| example_output = """example output: | |
| {"招式":"百丈飞瀑","description":"[player]翻身回剑,剑诀斜引,一招“百丈飞瀑”,剑锋从半空中直泻下来","missing":"[player]一咬牙,翻身回剑,剑诀斜引,一招“百丈飞瀑”,剑锋从半空中直泻下来"} | |
| {"招式":"百鸟朝凤","description":"[player]长剑一起,使一招“百鸟朝凤”,但见剑尖乱颤,霎时间便如化为数十个剑尖,罩住[target]中盘","missing":"[player]使一招“百鸟朝凤”,但见剑尖乱颤,霎时间便如化为数十个剑尖,向[target]飞去"} | |
| {"招式":"青山隐隐", "description":"[player]吸一口气,长剑中宫直进,剑尖不住颤动,剑到中途,忽然转而向上,乃是一招“青山隐隐”,端的是若有若无,变幻无方。","missing":"[player]吸一口气,长剑中宫直进,剑尖不住颤动,剑到中途,忽然转而向上,乃是一招“青山隐隐”,端的是若有若无,变幻无方。"} | |
| {"招式":"飞沙走石", "description":"长剑挺起,使一招“飞沙走石”,内劲直贯剑尖,寒光点点,挡的一声,击中的[target]胸口。","missing":"长剑挺起,使一招“飞沙走石”,内劲直贯剑尖,寒光点点,直向[target]胸口刺去。"}""" | |
| input = "input:\nmartial_art_name = " + martial_art_name + "\n" | |
| for m in movements: | |
| input += f"""{{"招式":"{m}"\}}\n""" | |
| messages = [ | |
| SystemMessage(content=smart_system_prompt), | |
| HumanMessage(content=task_message), | |
| HumanMessage(content=example_input), | |
| AIMessage(content=example_output), | |
| HumanMessage(content=input)] | |
| chat = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.1) | |
| response = chat(messages) | |
| return response.content | |
| def generate_skill_jsonl(json_data): | |
| major_skills = generate_skill_detail(json_data["major_martial_art"], json_data["major_movements"]) | |
| secondary_skills = generate_skill_detail(json_data["secondary_martial_art"], json_data["secondary_movements"]) | |
| all_skills = major_skills + "\n" + secondary_skills | |
| ans = "" | |
| lines = all_skills.split("\n") | |
| for line in lines: | |
| json_data = robust_parsing(line) | |
| if json_data is not None: | |
| json_str = json.dumps(json_data, ensure_ascii=False) | |
| ans += json_str + "\n" | |
| return ans | |
| import random | |
| class Player: | |
| def __init__(self, attr_json, skill_jsonl): | |
| self.name = attr_json["name"] | |
| self.STR = attr_json["STR"] | |
| self.SPD = attr_json["SPD"] | |
| self.VIT = attr_json["VIT"] | |
| if "major_damage" in attr_json: | |
| self.major_damage = attr_json["major_damage"] | |
| else: | |
| self.major_damage = 65 | |
| if "secondary_damage" in attr_json: | |
| self.secondary_damage = attr_json["secondary_damage"] | |
| else: | |
| self.secondary_damage = 50 | |
| self.normalize_attr() | |
| if "hp" in attr_json: | |
| self.hp = attr_json["hp"] | |
| else: | |
| self.hp = (self.VIT + 10) * 30 | |
| if "skills" in attr_json: | |
| self.skills = attr_json["skills"] | |
| else: | |
| self.skills = self.parsing_skill(skill_jsonl) | |
| self.original_json = attr_json | |
| def normalize_attr(self): | |
| max_attr_value = 20 | |
| min_attr_value = 0 | |
| regular_attr_sum = 30 | |
| xs = [self.STR, self.SPD, self.VIT] | |
| current_sum = 0 | |
| for i in range(3): | |
| xs[i] = min(max_attr_value, xs[i]) | |
| xs[i] = max(min_attr_value, xs[i]) | |
| current_sum += xs[i] | |
| if current_sum > regular_attr_sum: | |
| for i in range(3): | |
| xs[i] = round(xs[i] * regular_attr_sum / current_sum) | |
| elif current_sum < regular_attr_sum: | |
| for i in range(3): | |
| xs[i] = round(xs[i] * regular_attr_sum / current_sum) | |
| random_i = random.randint(0, 2) | |
| xs[random_i] = xs[random_i] + regular_attr_sum - sum(xs) | |
| self.STR = xs[0] | |
| self.SPD = xs[1] | |
| self.VIT = xs[2] | |
| def get_new_json(self): | |
| new_json = self.original_json | |
| new_json["STR"] = self.STR | |
| new_json["SPD"] = self.SPD | |
| new_json["VIT"] = self.VIT | |
| new_json["hp"] = self.hp | |
| new_json["skills"] = self.skills | |
| return new_json | |
| def parsing_skill(self, skill_jsonl): | |
| skills = [] | |
| lines = skill_jsonl.split("\n") | |
| for line in lines: | |
| if line.strip() == "": | |
| continue | |
| skill = json.loads(line) | |
| skills.append(skill) | |
| return skills | |
| 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} | |
| min_damage = 34 | |
| max_damage = 180 | |
| class GameManager: | |
| def __init__(self, attr_json1, attr_json2, skill_jsonl1, skill_jsonl2): | |
| self.player1 = Player(attr_json1, skill_jsonl1) | |
| self.player2 = Player(attr_json2, skill_jsonl2) | |
| def run(self): | |
| speed_diff = self.player1.SPD - self.player2.SPD | |
| if speed_diff == 0: | |
| speed_diff = random.randint(0, 3) * 2 - 3 | |
| skill_id_1 = random.randint(0, len(self.player1.skills) - 1) | |
| dmg_1 = 60 | |
| if skill_id_1 + skill_id_1 < len(self.player1.skills): | |
| dmg_1 = self.player1.major_damage | |
| else: | |
| dmg_1 = self.player1.secondary_damage | |
| skill_1_to_2 = self.player1.skills[skill_id_1] | |
| skill_1_to_2["dmg"] = dmg_1 | |
| skill_id_2 = random.randint(0, len(self.player2.skills) - 1) | |
| dmg_2 = 60 | |
| if skill_id_2 + skill_id_2 < len(self.player2.skills): | |
| dmg_2 = self.player2.major_damage | |
| else: | |
| dmg_2 = self.player2.secondary_damage | |
| skill_2_to_1 = self.player2.skills[skill_id_2] | |
| skill_2_to_1["dmg"] = dmg_2 | |
| # skill_2_to_1 = random.choice(self.player2.skills) | |
| # print(skill_1_to_2) | |
| # print(skill_2_to_1) | |
| damage_1_to_2 = self.compute_damage(skill_1_to_2, self.player1, self.player2) | |
| damage_2_to_1 = self.compute_damage(skill_2_to_1, self.player2, self.player1) | |
| ratio_1_to_2 = self.compute_ratio(skill_1_to_2, self.player1, self.player2) | |
| ratio_2_to_1 = self.compute_ratio(skill_2_to_1, self.player2, self.player1) | |
| if_hitted_1_to_2 = random.random() * 100.0 < ratio_1_to_2 | |
| if_hitted_2_to_1 = random.random() * 100.0 < ratio_2_to_1 | |
| desc_1_to_2 = skill_1_to_2["description"] if if_hitted_1_to_2 else skill_1_to_2["missing"] | |
| desc_1_to_2 = desc_1_to_2.replace("[player]", self.player1.name).replace("[target]", self.player2.name) | |
| if if_hitted_1_to_2: | |
| desc_1_to_2 += f"造成了{round(damage_1_to_2)}的伤害。" | |
| else: | |
| desc_1_to_2 += f"{self.player2.name}躲了过去" | |
| desc_2_to_1 = skill_2_to_1["description"] if if_hitted_2_to_1 else skill_2_to_1["missing"] | |
| desc_2_to_1 = desc_2_to_1.replace("[player]", self.player2.name).replace("[target]", self.player1.name) | |
| if if_hitted_2_to_1: | |
| desc_2_to_1 += f"造成了{round(damage_2_to_1)}的伤害。" | |
| else: | |
| desc_2_to_1 += f"{self.player1.name}躲了过去" | |
| self.flag = "continue" | |
| ans_msg = [] | |
| if self.player2.hp <= 0: | |
| ans_msg.append((None, f"{self.player2.name}战败了")) | |
| return ans_msg, self.player1.get_new_json(), self.player2.get_new_json() | |
| if self.player1.hp <= 0: | |
| ans_msg.append((f"{self.player1.name}战败了", None)) | |
| return ans_msg, self.player1.get_new_json(), self.player2.get_new_json() | |
| if speed_diff > 0: | |
| if if_hitted_1_to_2: | |
| self.player2.hp -= damage_1_to_2 | |
| ans_msg.append((desc_1_to_2, None)) | |
| if self.player2.hp > 0 and if_hitted_2_to_1: | |
| self.player1.hp -= damage_2_to_1 | |
| if self.player2.hp > 0: | |
| ans_msg.append((None, desc_2_to_1)) | |
| else: | |
| if if_hitted_2_to_1: | |
| self.player1.hp -= damage_2_to_1 | |
| ans_msg.append((None, desc_2_to_1)) | |
| if self.player1.hp > 0 and if_hitted_1_to_2: | |
| self.player2.hp -= damage_1_to_2 | |
| if self.player1.hp > 0: | |
| ans_msg.append((desc_1_to_2, None)) | |
| if self.player2.hp <= 0: | |
| ans_msg.append((None, f"{self.player2.name}战败了")) | |
| self.flag = "player1_win" | |
| if self.player1.hp <= 0: | |
| ans_msg.append((f"{self.player1.name}战败了", None)) | |
| self.flag = "player2_win" | |
| return ans_msg, self.player1.get_new_json(), self.player2.get_new_json() | |
| # default "damage": 60, "hit": 76, | |
| def compute_damage(self, skill, player, target): | |
| damage_ratio = skill["dmg"] | |
| damage_ratio = max(min_damage, damage_ratio) | |
| damage_ratio = min(max_damage, min_damage) | |
| skill_damage = damage_ratio + player.STR * 2 | |
| attack_diff = player.STR - target.VIT * 0.5 | |
| damage = skill_damage * (1 + 0.95 * (-0.5 + 1.0 / (1.0 + exp(-attack_diff / 6.0)))) | |
| return damage | |
| def compute_ratio(self, skill, player, target): | |
| damage_ratio = skill["dmg"] | |
| damage_ratio = round(damage_ratio) | |
| damage_ratio = max(min_damage, damage_ratio) | |
| damage_ratio = min(max_damage, min_damage) | |
| skill_hit = hit_map[damage_ratio] | |
| speed_diff = player.SPD - target.SPD | |
| hit_factor = (-0.5 + 1.0 / (1.0 + exp(-speed_diff / 6.0))) / 2.0 * max(30.0, skill_hit) | |
| return hit_factor + skill_hit | |
| fighter_save_name = 'LuotuoFighter.txt' | |
| import os | |
| datas = [] | |
| if not os.path.exists(fighter_save_name): | |
| data = { | |
| "name": "李鲁鲁", | |
| "attr_str": attr_lilulu, | |
| "skills": skill_lilulu | |
| } | |
| datas.append(data) | |
| data = { | |
| "name": "冷子昂", | |
| "attr_str": attr_lengziang, | |
| "skills": skill_lengziang | |
| } | |
| datas.append(data) | |
| data = { | |
| "name": "黄蓉", | |
| "attr_str": json_str_huangrong, | |
| "skills": skill_huangrong | |
| } | |
| datas.append(data) | |
| with open(fighter_save_name, 'w', encoding="utf-8") as f: | |
| for data in datas: | |
| f.write(json.dumps(data, ensure_ascii=False) + "\n") | |
| else: | |
| with open(fighter_save_name, 'r', encoding="utf-8") as f: | |
| for line in f.readlines(): | |
| data = json.loads(line) | |
| datas.append(data) | |
| fighter_data = datas | |
| elo_table = {} | |
| def get_unique_from_data(data): | |
| name = data["name"] | |
| json_data = json.loads(data["attr_str"]) | |
| return get_unique_from_json(name, json_data) | |
| def get_unique_from_json(name, json_data): | |
| 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: | |
| return name + "_" + str(json_data["major_damage"]) + "_" + str(json_data["secondary_damage"]) | |
| else: | |
| return None | |
| unique_to_score = {} | |
| name_to_top_unique = {} | |
| from math import exp | |
| elo_start = 1200 | |
| elo_K = 15 | |
| for data in fighter_data: | |
| unique_name = get_unique_from_data(data) | |
| score = elo_start | |
| unique_to_score[unique_name] = elo_start | |
| name = data["name"] | |
| name_to_top_unique[name] = unique_name | |
| def get_rank_str(top_n=20): | |
| global unique_to_score | |
| global name_to_top_unique | |
| score_name_pair = [] | |
| for name in name_to_top_unique: | |
| unique = name_to_top_unique[name] | |
| score = unique_to_score[unique] | |
| score_name_pair.append((unique, score)) | |
| top_n = min(top_n, len(name_to_top_unique)) | |
| score_name_pair.sort(key=lambda x: x[1], reverse=True) | |
| ans = "" | |
| for i in range(top_n): | |
| name = score_name_pair[i][0].split("_")[0] | |
| ans += f"第{i + 1}名" + name + " - " + str(round(score_name_pair[i][1])) + " | " | |
| return ans | |
| def update_elo(winner_unique, loser_unique): | |
| print(winner_unique + " wins " + loser_unique) | |
| update_winner = True | |
| update_loser = True | |
| global unique_to_score | |
| global name_to_top_unique | |
| if winner_unique not in unique_to_score: | |
| unique_to_score[winner_unique] = elo_start | |
| update_loser = False | |
| if loser_unique not in unique_to_score: | |
| unique_to_score[loser_unique] = elo_start | |
| Ra = unique_to_score[winner_unique] | |
| Rb = unique_to_score[loser_unique] | |
| Ea = 1 / (1 + exp((Rb - Ra) / 400)) | |
| Eb = 1 / (1 + exp((Ra - Rb) / 400)) | |
| Sa = 1 | |
| Sb = 0 | |
| unique_to_score[winner_unique] = Ra + elo_K * (Sa - Ea) | |
| unique_to_score[loser_unique] = Rb + elo_K * (Sb - Eb) | |
| winner_name = winner_unique.split("_")[0] | |
| if winner_name not in name_to_top_unique: | |
| name_to_top_unique[winner_name] = winner_unique | |
| winner_unique_on_rank = name_to_top_unique[winner_name] | |
| if unique_to_score[winner_unique] > unique_to_score[winner_unique_on_rank]: | |
| name_to_top_unique[winner_name] = winner_unique | |
| def get_random_fighter(): | |
| global fighter_data | |
| return random.choice(fighter_data) | |
| def searching_fighter(name): | |
| global fighter_data | |
| for data in fighter_data: | |
| if data["name"] == name: | |
| return data | |
| return get_random_fighter() | |
| def add_fighter(attr_json_str, skill_jsonl): | |
| attr_json = json.loads(attr_json_str) | |
| if "skills" in attr_json: | |
| del attr_json["skills"] | |
| if "hp" in attr_json: | |
| del attr_json["hp"] | |
| new_attr_json_str = json.dumps(attr_json, ensure_ascii=False) | |
| global fighter_data | |
| name = attr_json["name"] | |
| data = { | |
| "name": name, | |
| "attr_str": new_attr_json_str, | |
| "skills": skill_jsonl | |
| } | |
| fighter_data.append(data) | |
| print(json.dumps(data, ensure_ascii=False)) | |
| with open(fighter_save_name, 'a', encoding="utf-8") as f: | |
| f.write(json.dumps(data, ensure_ascii=False) + "\n") | |
| def searching_fighter_on_elo(name): | |
| global fighter_data | |
| global name_to_top_unique | |
| if name in name_to_top_unique: | |
| top_unique = name_to_top_unique[name] | |
| for data in fighter_data: | |
| if get_unique_from_data(data) == top_unique: | |
| return data | |
| return searching_fighter(name) | |
| else: | |
| return searching_fighter(name) | |
| import gradio as gr | |
| def get_attr_str_short(attr_json): | |
| if "hp" in attr_json: | |
| ans = "血量:" + str(attr_json["hp"]) + "\n" | |
| else: | |
| ans = "" | |
| ans += "力量:" + str(attr_json["STR"]) + "\n体质:" + str(attr_json["VIT"]) + "\n速度:" + str(attr_json["SPD"]) | |
| return ans | |
| def get_skill_str_short(attr_json): | |
| ans = attr_json["major_martial_art"] + ":\n" | |
| for skill in attr_json["major_movements"]: | |
| ans += skill + "-" | |
| ans += "\n" + attr_json["secondary_martial_art"] + ":\n" | |
| for skill in attr_json["secondary_movements"]: | |
| ans += skill + "-" | |
| ans += "\n 防御:" + attr_json["footwork_and_body_method"] | |
| return ans | |
| def generate_ma(name, desc, display_board): | |
| if name.strip() == "": | |
| return "", "", "", "", display_board, "角色名不能为空,输入角色名后生成功法或者创建角色" | |
| status = "请为角色进一步生成详细功法" | |
| role_detail = ma_foo_answer | |
| if name == "李鲁鲁": | |
| json_answer = json.loads(attr_lilulu) | |
| elif name == "冷子昂": | |
| json_answer = json.loads(attr_lengziang) | |
| else: | |
| role_detail = generate_detailed_description(name, desc) | |
| json_str = generate_attr_json(name, desc, role_detail) | |
| json_answer = robust_parsing(json_str) | |
| json_answer_str = json.dumps(json_answer, ensure_ascii=False) | |
| skill_desc = get_skill_str_short(json_answer) | |
| display_board.append(("生成人物" + json_answer["name"] + "\n" + skill_desc, None)) | |
| return role_detail, json_answer_str, get_attr_str_short(json_answer), skill_desc, display_board, status | |
| def generate_madetail(player_attribute, display_board): | |
| if player_attribute.strip() == "": | |
| return "", display_board, "需要生成武功名称,再生成描述。或者直接随机召唤角色" | |
| status = "确认两个角色都生成之后,可以进入战斗" | |
| json_answer = json.loads(player_attribute) | |
| generate_flag = False | |
| ans = skill_foo_desc | |
| if json_answer["name"] == "李鲁鲁": | |
| ans = skill_lilulu | |
| elif json_answer["name"] == "冷子昂": | |
| ans = skill_lengziang | |
| else: | |
| ans = generate_skill_jsonl(json_answer) | |
| generate_flag = True | |
| display_board.append(("为" + json_answer["name"] + "生成详细的功法描述\n", None)) | |
| if generate_flag: | |
| player = Player(json_answer, ans) | |
| unique_name = get_unique_from_json(json_answer["name"], json_answer) | |
| if len(player.skills) > 1 and unique_name != None: | |
| add_fighter(player_attribute, ans) | |
| display_board.append(("将新角色" + json_answer["name"] + "录入到数据库\n", None)) | |
| return ans, display_board, status | |
| def continue_fight(detailed_attr_player1, detailed_attr_player2, detailed_skill_player1, detailed_skill_player2, | |
| display_board): | |
| if detailed_attr_player1.strip() == "" or detailed_attr_player2.strip() == "" or detailed_skill_player1.strip() == "" or detailed_skill_player2.strip() == "": | |
| str1 = "" | |
| if detailed_attr_player1.strip() != "": | |
| str1 = get_attr_str_short(json.loads(detailed_attr_player1)) | |
| str2 = "" | |
| if detailed_attr_player2.strip() != "": | |
| str2 = get_attr_str_short(json.loads(detailed_attr_player2)) | |
| return detailed_attr_player1, detailed_attr_player2, display_board, str1, str2, "请重新检查人物的生成情况" | |
| json1 = json.loads(detailed_attr_player1) | |
| json2 = json.loads(detailed_attr_player2) | |
| name1 = json1["name"] | |
| name2 = json2["name"] | |
| status = f"""{name1} 大战 {name2}""" | |
| if "hp" in json1 and "hp" in json2: | |
| if json1["hp"] <= 0 and json1["hp"] < json2["hp"]: | |
| unique1 = get_unique_from_json(name1, json1) | |
| unique2 = get_unique_from_json(name2, json2) | |
| return detailed_attr_player1, detailed_attr_player2, display_board, "", "", "战斗结束!请清除战斗或者重新生成人物" | |
| if json2["hp"] <= 0 and json2["hp"] < json1["hp"]: | |
| unique1 = get_unique_from_json(name1, json1) | |
| unique2 = get_unique_from_json(name2, json2) | |
| return detailed_attr_player1, detailed_attr_player2, display_board, "", "", "战斗结束!请清除战斗或者重新生成人物" | |
| game_manager = GameManager(json1, json2, detailed_skill_player1, detailed_skill_player2) | |
| msgs, new_player1, new_player2 = game_manager.run() | |
| for msg in msgs: | |
| display_board.append(msg) | |
| if game_manager.flag == "player1_win": | |
| unique1 = get_unique_from_json(name1, json1) | |
| unique2 = get_unique_from_json(name2, json2) | |
| update_elo(unique1, unique2) | |
| elif game_manager.flag == "player2_win": | |
| unique1 = get_unique_from_json(name1, json1) | |
| unique2 = get_unique_from_json(name2, json2) | |
| update_elo(unique2, unique1) | |
| new_player1_str = json.dumps(new_player1, ensure_ascii=False) | |
| new_player2_str = json.dumps(new_player2, ensure_ascii=False) | |
| return new_player1_str, new_player2_str, display_board, get_attr_str_short(new_player1), get_attr_str_short( | |
| new_player2), status | |
| def callback_random_role(display_board): | |
| data = get_random_fighter() | |
| name = data["name"] | |
| json_str = data["attr_str"] | |
| skills_jsonl = data["skills"] | |
| json_answer = json.loads(json_str) | |
| display_board.append(("从数据库选择角色" + name, None)) | |
| return name, json_str, skills_jsonl, get_attr_str_short(json_answer), get_skill_str_short( | |
| json_answer), display_board | |
| def callback_role_from_name(display_board, name): | |
| data = searching_fighter_on_elo(name) | |
| json_str = data["attr_str"] | |
| skills_jsonl = data["skills"] | |
| json_answer = json.loads(json_str) | |
| display_board.append(("从数据库选择角色" + name, None)) | |
| return name, json_str, skills_jsonl, get_attr_str_short(json_answer), get_skill_str_short( | |
| json_answer), display_board | |
| def callback_clean_fight(display_board, detailed_attr_player1, detailed_attr_player2): | |
| display_board = [] | |
| json1 = json.loads(detailed_attr_player1) | |
| json2 = json.loads(detailed_attr_player2) | |
| if "hp" in json1: | |
| del json1["hp"] | |
| if "hp" in json2: | |
| del json2["hp"] | |
| new_detailed_attr_player1 = json.dumps(json1, ensure_ascii=False) | |
| new_detailed_attr_player2 = json.dumps(json2, ensure_ascii=False) | |
| return display_board, new_detailed_attr_player1, new_detailed_attr_player2 | |
| def callback_refresh_rank(): | |
| return get_rank_str() | |
| with gr.Blocks() as demo: | |
| gr.Markdown( | |
| """ | |
| # LuotuoFighter | |
| ## 骆驼大乱斗 | |
| Implemented by 李鲁鲁 | |
| 项目链接 https://github.com/LC1332/Chat-Haruhi-Suzumiya | |
| 这个原型是为了百川Hackathon而初步建立 | |
| 三种角色建立方式: 根据姓名召唤、随机召唤,或者输入姓名和描述后生成新的人物 | |
| 姓名召唤会召唤同名人物中战力最强的那个 | |
| 由于Gradio特性,建立角色要花个几十秒,先点击生成功法,再点击生成功法描述 | |
| """ | |
| ) | |
| with gr.Row(): | |
| with gr.Column(): | |
| current_status = gr.Textbox(label="当前状态", value="请输入角色1的姓名之后生成功法,或进行召唤") | |
| display_board = gr.Chatbot(height=800) | |
| submit_fight2 = gr.Button("继续战斗!") | |
| clean_fight = gr.Button("清空战斗") | |
| with gr.Column(): | |
| with gr.Row(): | |
| name_player1 = gr.Textbox(label="角色1姓名", scale=1, interactive=True, value="李鲁鲁") | |
| desc_player1 = gr.Textbox(label="角色1描述", scale=20, value="师从,主修剑法", interactive=True) | |
| with gr.Row(): | |
| generate_ma_player1 = gr.Button("生成功法") | |
| generate_madetail_player1 = gr.Button("生成功法描述") | |
| with gr.Row(): | |
| random_sel_player1 = gr.Button("随机召唤") | |
| call_player1_with_name1 = gr.Button("根据姓名召唤") | |
| with gr.Row(): | |
| name_player2 = gr.Textbox(label="角色2姓名", scale=1, interactive=True, value="冷子昂") | |
| desc_player2 = gr.Textbox(label="角色2描述", scale=20, value="师从,主修剑法", interactive=True) | |
| with gr.Row(): | |
| generate_ma_player2 = gr.Button("生成功法") | |
| generate_madetail_player2 = gr.Button("生成功法描述") | |
| with gr.Row(): | |
| random_sel_player2 = gr.Button("随机召唤2") | |
| call_player1_with_name2 = gr.Button("根据姓名召唤2") | |
| with gr.Row(): | |
| submit_fight = gr.Button("继续战斗!") | |
| with gr.Row(): | |
| attr_player1 = gr.TextArea(label="角色1属性") | |
| skill_player1 = gr.TextArea(label="角色1功法描述") | |
| with gr.Row(): | |
| attr_player2 = gr.TextArea(label="角色2属性") | |
| skill_player2 = gr.TextArea(label="角色2功法描述") | |
| with gr.Row(): | |
| refresh_rank = gr.Button("刷新天梯") | |
| with gr.Row(): | |
| rank_showboard = gr.TextArea(label="天梯") | |
| with gr.Row(): | |
| with gr.Column(): | |
| detailed_description_player1 = gr.TextArea(label="角色1具体描述") | |
| detailed_skill_player1 = gr.TextArea(label="角色1技能json") | |
| detailed_attr_player1 = gr.TextArea(label="角色1属性json") | |
| with gr.Column(): | |
| detailed_description_player2 = gr.TextArea(label="角色2具体描述") | |
| detailed_skill_player2 = gr.TextArea(label="角色2技能json") | |
| detailed_attr_player2 = gr.TextArea(label="角色2属性json") | |
| 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]) | |
| 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]) | |
| generate_madetail_player1.click(fn=generate_madetail, inputs=[detailed_attr_player1, display_board], | |
| outputs=[detailed_skill_player1, display_board, current_status]) | |
| generate_madetail_player2.click(fn=generate_madetail, inputs=[detailed_attr_player2, display_board], | |
| outputs=[detailed_skill_player2, display_board, current_status]) | |
| 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]) | |
| 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]) | |
| 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]) | |
| 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]) | |
| refresh_rank.click(fn=callback_refresh_rank, inputs=[], outputs=[rank_showboard]) | |
| clean_fight.click(fn=callback_clean_fight, inputs=[display_board, detailed_attr_player1, detailed_attr_player2], | |
| outputs=[display_board, detailed_attr_player1, detailed_attr_player2]) | |
| submit_fight.click(fn=continue_fight, | |
| inputs=[detailed_attr_player1, detailed_attr_player2, detailed_skill_player1, | |
| detailed_skill_player2, display_board], | |
| outputs=[detailed_attr_player1, detailed_attr_player2, display_board, attr_player1, attr_player2, | |
| current_status]) | |
| submit_fight2.click(fn=continue_fight, | |
| inputs=[detailed_attr_player1, detailed_attr_player2, detailed_skill_player1, | |
| detailed_skill_player2, display_board], | |
| outputs=[detailed_attr_player1, detailed_attr_player2, display_board, attr_player1, | |
| attr_player2, current_status]) | |
| demo.launch(debug=False, share=True) | |