File size: 9,036 Bytes
b1e12f0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dcd204e
b1e12f0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dcd204e
 
 
 
 
b1e12f0
 
 
dcd204e
 
b1e12f0
 
 
 
 
 
 
 
 
 
 
dcd204e
 
 
b1e12f0
 
 
 
 
 
 
 
dcd204e
 
b1e12f0
 
 
 
 
 
 
 
 
dcd204e
b1e12f0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dcd204e
 
 
 
 
 
 
 
b1e12f0
dcd204e
b1e12f0
 
 
 
 
 
dcd204e
b1e12f0
 
 
 
 
 
 
 
 
 
 
dcd204e
 
b1e12f0
 
dcd204e
b1e12f0
 
 
 
 
 
 
 
dcd204e
b1e12f0
 
 
dcd204e
 
b1e12f0
dcd204e
 
b1e12f0
dcd204e
 
 
 
 
 
 
 
b1e12f0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dcd204e
b1e12f0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f9082a4
dcd204e
f9082a4
b1e12f0
 
 
f9082a4
b1e12f0
f9082a4
 
 
 
 
 
b1e12f0
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# murder_mystery.py

import random
import gradio as gr
from huggingface_hub import InferenceClient

model_name = "Qwen/Qwen2.5-72B-Instruct"
client = InferenceClient(model_name)

def llm_inference(messages):
    eos_token = "<|endoftext|>"
    output = client.chat.completions.create(
        messages=messages,
        stream=False,
        temperature=0.7,
        top_p=0.1,
        max_tokens=512,
        stop=[eos_token]
    )
    response = ''
    for choice in output.choices:
        response += choice['message']['content']
    return response

suspects = {
    "Colonel Mustard": {
        "personality": "",
        "knowledge": "",
        "is_murderer": False
    },
    "Miss Scarlett": {
        "personality": "",
        "knowledge": "",
        "is_murderer": False
    },
    "Professor Plum": {
        "personality": "",
        "knowledge": "",
        "is_murderer": False
    },
    "Mrs. Peacock": {
        "personality": "",
        "knowledge": "",
        "is_murderer": False
    },
    "Mr. Green": {
        "personality": "",
        "knowledge": "",
        "is_murderer": False
    },
    "Dr. Orchid": {
        "personality": "",
        "knowledge": "",
        "is_murderer": False
    }
}

weapons = ["Candlestick", "Dagger", "Lead Pipe", "Revolver", "Rope", "Wrench", "Poison"]
locations = ["Kitchen", "Ballroom", "Conservatory", "Dining Room", "Library", "Study", "Billiard Room", "Lounge"]

possible_personalities = [
    "stern and suspicious",
    "charming but evasive",
    "intellectual and nervous",
    "gracious but secretive",
    "amiable yet deceptive",
    "hot-headed and impulsive",
    "calm and collected",
    "mysterious and aloof",
    "jovial but cunning",
    "nervous and jittery",
    "sarcastic and witty",
    "arrogant and dismissive"
]

game_state = {
    "murderer": "",
    "weapon": "",
    "location": "",
    "is_game_over": False,
    "clues": [],
    "history": [],
    "accused": False
}

def initialize_game():
    game_state["murderer"] = random.choice(list(suspects.keys()))
    game_state["weapon"] = random.choice(weapons)
    game_state["location"] = random.choice(locations)
    game_state["is_game_over"] = False
    game_state["clues"] = []
    game_state["history"] = []
    game_state["accused"] = False
    personalities_copy = possible_personalities.copy()
    random.shuffle(personalities_copy)
    for i, suspect in enumerate(suspects):
        suspects[suspect]["is_murderer"] = (suspect == game_state["murderer"])
        suspects[suspect]["personality"] = personalities_copy[i % len(personalities_copy)]
        suspects[suspect]["knowledge"] = generate_knowledge(suspect)
    print(f"Debug: Murderer is {game_state['murderer']}, Weapon is {game_state['weapon']}, Location is {game_state['location']}")
    for suspect in suspects:
        print(f"Debug: {suspect}'s personality is {suspects[suspect]['personality']}")

def generate_knowledge(suspect_name):
    knowledge = []
    if suspects[suspect_name]["is_murderer"]:
        knowledge.append("You are the murderer. Deflect suspicion subtly.")
    else:
        known_elements = []
        elements = ["weapon", "location", "murderer"]
        random.shuffle(elements)
        known_item = elements[0]
        if known_item == "weapon":
            known_elements.append(f"You know that the weapon is {game_state['weapon']}.")
        elif known_item == "location":
            known_elements.append(f"You know that the location is {game_state['location']}.")
        elif known_item == "murderer":
            not_murderer = random.choice([s for s in suspects if s != suspect_name and s != game_state["murderer"]])
            known_elements.append(f"You know that {not_murderer} is not the murderer.")
        knowledge.extend(known_elements)
    return ' '.join(knowledge)

def get_ai_response(suspect_name, player_input):
    personality = suspects[suspect_name]["personality"]
    knowledge = suspects[suspect_name]["knowledge"]
    system_prompt = f"You are {suspect_name}, who is {personality}. {knowledge} When answering questions, you may reveal hints subtly based on what you know."
    user_message = f"The detective asks: \"{player_input}\" As {suspect_name}, respond in first person, staying in character."
    messages = [
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": user_message}
    ]
    response = llm_inference(messages)
    return response.strip()

def process_input(player_input):
    if game_state["is_game_over"]:
        return "The game is over. Please restart to play again.", game_state["history"]
    if game_state["accused"]:
        return "You have already made an accusation. Please restart to play again.", game_state["history"]
    game_state["history"].append(("Detective", player_input))
    if "accuse" in player_input.lower():
        game_state["accused"] = True
        result = handle_accusation(player_input)
        game_state["history"].append(("System", result))
        return result, game_state["history"]
    else:
        for suspect in suspects:
            if suspect.lower() in player_input.lower():
                ai_response = get_ai_response(suspect, player_input)
                game_state["history"].append((suspect, ai_response))
                extract_clues(ai_response)
                return ai_response, game_state["history"]
        return "Please direct your question to a suspect.", game_state["history"]

def extract_clues(ai_response):
    clues = []
    for weapon in weapons:
        if weapon.lower() in ai_response.lower() and weapon != game_state["weapon"]:
            clues.append(f"The weapon is not the {weapon}.")
    for location in locations:
        if location.lower() in ai_response.lower() and location != game_state["location"]:
            clues.append(f"The location is not the {location}.")
    for suspect in suspects:
        if suspect.lower() in ai_response.lower() and suspect != game_state["murderer"]:
            clues.append(f"{suspect} is not the murderer.")
    for clue in clues:
        if clue not in game_state["clues"]:
            game_state["clues"].append(clue)

def handle_accusation(player_input):
    suspect_guess = None
    weapon_guess = None
    location_guess = None
    for suspect in suspects:
        if suspect.lower() in player_input.lower():
            suspect_guess = suspect
            break
    for weapon in weapons:
        if weapon.lower() in player_input.lower():
            weapon_guess = weapon
            break
    for location in locations:
        if location.lower() in player_input.lower():
            location_guess = location
            break
    if (suspect_guess == game_state["murderer"] and
        weapon_guess == game_state["weapon"] and
        location_guess == game_state["location"]):
        game_state["is_game_over"] = True
        return f"Congratulations! You solved the case. It was {suspect_guess} with the {weapon_guess} in the {location_guess}."
    else:
        game_state["is_game_over"] = True
        return f"Incorrect accusation! You lose. The real murderer was {game_state['murderer']} with the {game_state['weapon']} in the {game_state['location']}."

def chat_interface(player_input):
    response, history = process_input(player_input)
    chat_history = ""
    for speaker, text in history:
        chat_history += f"**{speaker}:** {text}\n\n"
    clues_display = "\n".join(game_state["clues"])
    return chat_history, clues_display

def restart_game():
    initialize_game()
    return "", ""

with gr.Blocks() as demo:
    gr.Markdown("# Murder Mystery Game")
    with gr.Row():
        with gr.Column():
            gr.Markdown("## Commands")
            gr.Markdown("- **Ask a question to a suspect**: Include the suspect's name in your question.\n  Example: *\"Miss Scarlett, where were you during the evening?\"*")
            gr.Markdown("- **Make an accusation**: Include the word *\"accuse\"*.\n  Example: *\"I accuse Colonel Mustard with the Rope in the Study.\"*")
            player_input = gr.Textbox(lines=1, label="Your Input")
            send_button = gr.Button("Send")
            restart_button = gr.Button("Restart Game")
            chatbox = gr.Textbox(lines=15, label="Chat History", interactive=False)
        with gr.Column():
            gr.Markdown("## Suspects")
            gr.Markdown(', '.join(suspects.keys()))
            gr.Markdown("## Weapons")
            gr.Markdown(', '.join(weapons))
            gr.Markdown("## Locations")
            gr.Markdown(', '.join(locations))
            clues = gr.Textbox(lines=15, label="Discovered Clues", interactive=False)

    def send_message(player_input):
        chat_history, clues_display = chat_interface(player_input)
        return chat_history, "", clues_display

    send_button.click(send_message, inputs=player_input, outputs=[chatbox, player_input, clues])
    restart_button.click(fn=restart_game, inputs=None, outputs=[chatbox, clues])

initialize_game()
demo.launch()