File size: 6,545 Bytes
7418c14
 
 
075b4b2
abb2690
dc0fd01
73bfbed
 
 
 
a3768e0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73bfbed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7418c14
075b4b2
10d6aa1
2c80a62
bc61848
 
 
2c80a62
10d6aa1
2c80a62
bc61848
10d6aa1
 
 
2c80a62
10d6aa1
2c80a62
bc61848
10d6aa1
 
7418c14
075b4b2
94172b1
10d6aa1
 
 
cab2759
 
2c80a62
10d6aa1
6afba73
bc61848
 
2c80a62
bc61848
 
 
 
2c80a62
 
 
 
c216029
10d6aa1
 
 
 
 
 
2c80a62
10d6aa1
 
 
2c80a62
10d6aa1
c216029
2c80a62
 
 
 
 
 
cab2759
2c80a62
abb2690
10d6aa1
 
2c80a62
 
10d6aa1
210d467
cab2759
 
 
 
 
 
 
 
f941683
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
import gradio as gr
import pandas as pd
import numpy as np
from xgboost import Booster, DMatrix
import requests

# Generate card_numbers
card_numbers = {
    "Archers": 1, "Archer Queen": 2, "Baby Dragon": 3, "Balloon": 4, "Bandit": 5, "Barbarians": 6,
    "Bats": 7, "Battle Healer": 8, "Battle Ram": 9, "Bomber": 10, "Bowler": 11, "Bush Goblins": 12,
    "Cannon Cart": 13, "Cursed Hog": 14, "Dark Prince": 15, "Dart Goblin": 16, "Electro Dragon": 17,
    "Electro Giant": 18, "Electro Spirit": 19, "Electro Wizard": 20, "Elite Barbarians": 21,
    "Elixir Blob": 22, "Elixir Golem": 23, "Elixir Golemite": 24, "Executioner": 25, "Firecracker": 26,
    "Fire Spirit": 27, "Fisherman": 28, "Flying Machine": 29, "Giant": 30, "Giant Skeleton": 31,
    "Goblin Brawler": 32, "Goblin Gang": 33, "Goblin Demolisher": 34, "Goblin Giant": 35,
    "Goblin Machine": 36, "Goblins": 37, "Goblinstein": 38, "Golden Knight": 39, "Golem": 40,
    "Golemite": 41, "Guardienne": 42, "Guards": 43, "Hog Rider": 44, "Hunter": 45, "Heal Spirit": 46,
    "Ice Golem": 47, "Ice Spirit": 48, "Ice Wizard": 49, "Inferno Dragon": 50, "Knight": 51,
    "Lava Hound": 52, "Lava Pup": 53, "Little Prince": 54, "Lumberjack": 55, "Magic Archer": 56,
    "Mega Knight": 57, "Mega Minion": 58, "Mighty Miner": 59, "Miner": 60, "Mini P.E.K.K.A.": 61,
    "Minion Horde": 62, "Minions": 63, "Monk": 64, "Mother Witch": 65, "Monster": 66, "Musketeer": 67,
    "Night Witch": 68, "P.E.K.K.A.": 69, "Phoenix": 70, "Reborn Phoenix": 71, "Prince": 72,
    "Princess": 73, "Ram Rider": 74, "Rascal Boy": 75, "Rascal Girl": 76, "Royal Ghost": 77,
    "Royal Giant": 78, "Royal Hogs": 79, "Royal Recruits": 80, "Skeleton Army": 81,
    "Skeleton Barrel": 82, "Skeleton Dragons": 83, "Skeleton King": 84, "Skeletons": 85, "Sparky": 86,
    "Spear Goblins": 87, "Suspicious Bush": 88, "Three Musketeers": 89, "Valkyrie": 90,
    "Wall Breakers": 91, "Witch": 92, "Wizard": 93, "Zappies": 94, "Bomb Tower": 95, "Cannon": 96,
    "Inferno Tower": 98, "Mortar": 99, "Tesla": 100, "X-Bow": 101, "Barbarian Hut": 102,
    "Elixir Collector": 103, "Furnace": 104, "Goblin Cage": 105, "Goblin Drill": 106,
    "Goblin Hut": 107, "Phoenix Egg": 108, "Tombstone": 109, "Arrows": 110, "Barbarian Barrel": 111,
    "Earthquake": 112, "Fireball": 113, "Freeze": 114, "Giant Snowball": 115, "Lightning": 117,
    "Poison": 118, "Rage": 119, "Rocket": 120, "Royal Delivery": 121, "The Log": 122, "Tornado": 123,
    "Zap": 125, "Goblin Barrel": 132, "Graveyard": 139
}

# Generate card_images with normalized filenames
base_url = "https://raw.githubusercontent.com/RoyaleAPI/cr-api-assets/master/cards/"
card_images = {
    card_name: f"{base_url}{card_name.lower().replace(' ', '-').replace('/', '-').replace('.', '')}.png"
    for card_name in card_numbers.keys()
}

# Validate URLs
valid_card_images = {}
for card, url in card_images.items():
    response = requests.head(url)
    if response.status_code == 200:
        valid_card_images[card] = url

# Define model-related functions
MODEL_PATH = "model.json"

def load_model(model_path):
    """Load the saved XGBoost model."""
    model = Booster()
    model.load_model(model_path)
    return model

def deck_to_ids(deck, mapping):
    """Convert card names to IDs based on the mapping."""
    return [mapping.get(card, 0) - 1 for card in deck]

def preprocess_deck(deck):
    """Prepare the selected deck for the model."""
    deck_ids = deck_to_ids(deck, card_numbers)
    num_choices = len(card_numbers)
    one_hot = np.zeros(num_choices, dtype=int)
    one_hot[np.array(deck_ids)] = 1
    features = np.concatenate(([0, 0], one_hot))
    return pd.DataFrame([features])

def predict_outcome(opponent_deck):
    """Make a prediction based on the opponent's deck."""
    deck_data = preprocess_deck(opponent_deck)
    dmatrix = DMatrix(deck_data)
    prediction = model.predict(dmatrix)
    return f"Probability of Winning: {prediction[0] * 100:.2f}%"

# Load the model
model = load_model(MODEL_PATH)

# Create Gradio Interface
with gr.Blocks(css="""
    .card-container img {
        width: 80px !important;
        height: 80px !important;
        object-fit: contain;
        margin: 5px auto;
    }
    .card-container {
        text-align: center;
        padding: 5px;
        border: 1px solid #ddd;
        border-radius: 8px;
        margin: 5px;
    }
    .checkbox-container {
        margin-top: 5px;
    }
""") as interface:
    gr.Markdown("## Clash Royale Prediction")
    gr.Markdown("Select 8 cards from the opponent's deck to predict the probability of winning!")

    # State for tracking selected cards
    selected_cards_display = gr.Markdown("Selected cards: 0/8")

    def update_selection(*checkbox_values):
        selected_count = sum(checkbox_values)
        return f"Selected cards: {selected_count}/8"

    # Create card grid using rows and columns
    cards_per_row = 8
    cards_list = list(valid_card_images.items())
    all_checkboxes = []
    
    for i in range(0, len(cards_list), cards_per_row):
        with gr.Row():
            for card, url in cards_list[i:i + cards_per_row]:
                with gr.Column(elem_classes="card-container"):
                    gr.Image(value=url, show_label=False)
                    checkbox = gr.Checkbox(label=card, elem_classes="checkbox-container")
                    all_checkboxes.append(checkbox)

    with gr.Row():
        result = gr.Textbox(label="Prediction Result:", interactive=False)
        clear_btn = gr.Button("Clear Selection")
        predict_btn = gr.Button("Make Prediction", variant="primary")

    def clear_selection():
        return [False] * len(all_checkboxes) + ["Selected cards: 0/8", ""]

    clear_btn.click(
        clear_selection,
        outputs=all_checkboxes + [selected_cards_display, result]
    )

    def validate_and_predict(*checkbox_values):
        selected_cards = [
            card for card, checked in zip(valid_card_images.keys(), checkbox_values)
            if checked
        ]
        if len(selected_cards) != 8:
            return f"Error: Please select exactly 8 cards. You selected {len(selected_cards)}."
        return predict_outcome(selected_cards)

    predict_btn.click(
        validate_and_predict,
        inputs=all_checkboxes,
        outputs=result
    )

    # Update the card count display
    for checkbox in all_checkboxes:
        checkbox.change(
            update_selection,
            inputs=all_checkboxes,
            outputs=selected_cards_display
        )

interface.launch()