Генератор колоды Beta
This commit is contained in:
@@ -35,7 +35,7 @@ bundle exec hanami db prepare
|
|||||||
```bat
|
```bat
|
||||||
bundle exec puma -C config/puma.rb config.ru
|
bundle exec puma -C config/puma.rb config.ru
|
||||||
```
|
```
|
||||||
cd
|
|
||||||
Открыть: [http://localhost:2300](http://localhost:2300)
|
Открыть: [http://localhost:2300](http://localhost:2300)
|
||||||
|
|
||||||
## Важно про SQLite для Hanami
|
## Важно про SQLite для Hanami
|
||||||
|
|||||||
54
app/actions/decks/generate.rb
Normal file
54
app/actions/decks/generate.rb
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module ClashDeckGenerator2
|
||||||
|
module Actions
|
||||||
|
module Decks
|
||||||
|
class Generate < ClashDeckGenerator2::Action
|
||||||
|
include Deps[view: "views.home.index"]
|
||||||
|
|
||||||
|
def handle(_req, res)
|
||||||
|
roles_repo = ClashDeckGenerator2::Services::CardRolesRepository.new
|
||||||
|
cards_repo = ClashDeckGenerator2::Repos::CardsRepo.new
|
||||||
|
|
||||||
|
generator = ClashDeckGenerator2::Services::DeckGenerator.new(
|
||||||
|
cards_repo: cards_repo,
|
||||||
|
roles_repo: roles_repo
|
||||||
|
)
|
||||||
|
|
||||||
|
deck = unwrap(generator.call)
|
||||||
|
|
||||||
|
res.render(
|
||||||
|
view,
|
||||||
|
deck: deck,
|
||||||
|
roles_repo: roles_repo,
|
||||||
|
stats: build_stats(deck)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def unwrap(result)
|
||||||
|
if result.is_a?(Array) && result.first == :cards
|
||||||
|
result.last
|
||||||
|
else
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_stats(deck)
|
||||||
|
{
|
||||||
|
cards_count: deck.size,
|
||||||
|
average_elixir: (deck.sum(&:elixir_cost).to_f / deck.size).round(2),
|
||||||
|
spells_count: deck.count { |c| c.type == "spell" },
|
||||||
|
troops_count: deck.count { |c| c.type == "troop" },
|
||||||
|
buildings_count: deck.count { |c| c.type == "building" },
|
||||||
|
champions_count: deck.count { |c| c.rarity == "champion" },
|
||||||
|
heroes_count: deck.count { |c| c.rarity == "hero" },
|
||||||
|
evolutions_count: deck.count { |c| c.rarity == "evolution" },
|
||||||
|
meta_cards_count: deck.count { |c| c.is_meta == 1 }
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
12
app/actions/home/index.rb
Normal file
12
app/actions/home/index.rb
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module ClashDeckGenerator2
|
||||||
|
module Actions
|
||||||
|
module Home
|
||||||
|
class Index < ClashDeckGenerator2::Action
|
||||||
|
def handle(_req, _res)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -5,11 +5,15 @@ module ClashDeckGenerator2
|
|||||||
class DeckGenerator
|
class DeckGenerator
|
||||||
DEFAULT_RULES = {
|
DEFAULT_RULES = {
|
||||||
deck_size: 8,
|
deck_size: 8,
|
||||||
min_spells: 1,
|
|
||||||
min_troops: 1,
|
min_troops: 1,
|
||||||
max_buildings: 2,
|
max_buildings: 2,
|
||||||
min_avg_elixir: 2.5,
|
min_avg_elixir: 2.5,
|
||||||
max_avg_elixir: 5.0
|
max_avg_elixir: 5.0,
|
||||||
|
min_meta_cards: 4,
|
||||||
|
max_meta_cards: 8,
|
||||||
|
min_win_conditions: 1,
|
||||||
|
min_anti_air: 1,
|
||||||
|
min_spell_roles: 1
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
SPECIAL_COMBINATIONS = [
|
SPECIAL_COMBINATIONS = [
|
||||||
@@ -17,8 +21,13 @@ module ClashDeckGenerator2
|
|||||||
{ evolutions: 2, specials: 1 }
|
{ evolutions: 2, specials: 1 }
|
||||||
].freeze
|
].freeze
|
||||||
|
|
||||||
def initialize(cards_repo: ClashDeckGenerator2::Repos::CardsRepo.new, rules: {})
|
def initialize(
|
||||||
|
cards_repo: ClashDeckGenerator2::Repos::CardsRepo.new,
|
||||||
|
roles_repo: ClashDeckGenerator2::Services::CardRolesRepository.new,
|
||||||
|
rules: {}
|
||||||
|
)
|
||||||
@cards_repo = cards_repo
|
@cards_repo = cards_repo
|
||||||
|
@roles_repo = roles_repo
|
||||||
@rules = DEFAULT_RULES.merge(rules)
|
@rules = DEFAULT_RULES.merge(rules)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -30,21 +39,9 @@ module ClashDeckGenerator2
|
|||||||
|
|
||||||
evolution_cards = cards.select { |card| card.rarity == "evolution" }
|
evolution_cards = cards.select { |card| card.rarity == "evolution" }
|
||||||
special_cards = cards.select { |card| %w[hero champion].include?(card.rarity) }
|
special_cards = cards.select { |card| %w[hero champion].include?(card.rarity) }
|
||||||
regular_cards = cards.reject { |card| ["evolution", "hero", "champion"].include?(card.rarity) }
|
regular_cards = cards.reject { |card| %w[evolution hero champion].include?(card.rarity) }
|
||||||
|
|
||||||
def enough_win_conditions?(deck)
|
attempts = 5000
|
||||||
deck.count { |card| has_role?(card, "win_condition") } >= 1
|
|
||||||
end
|
|
||||||
|
|
||||||
def enough_anti_air?(deck)
|
|
||||||
deck.count { |card| has_role?(card, "anti_air") } >= 1
|
|
||||||
end
|
|
||||||
|
|
||||||
def has_role?(card, role)
|
|
||||||
@roles_repo.has_role?(card.name, role)
|
|
||||||
end
|
|
||||||
|
|
||||||
attempts = 1000
|
|
||||||
|
|
||||||
attempts.times do
|
attempts.times do
|
||||||
combo = SPECIAL_COMBINATIONS.sample
|
combo = SPECIAL_COMBINATIONS.sample
|
||||||
@@ -56,15 +53,18 @@ end
|
|||||||
chosen_specials = special_cards.sample(combo[:specials])
|
chosen_specials = special_cards.sample(combo[:specials])
|
||||||
|
|
||||||
used_names = (chosen_evolutions + chosen_specials).map(&:name)
|
used_names = (chosen_evolutions + chosen_specials).map(&:name)
|
||||||
|
|
||||||
remaining_pool = regular_cards.reject { |card| used_names.include?(card.name) }
|
remaining_pool = regular_cards.reject { |card| used_names.include?(card.name) }
|
||||||
remaining_needed = @rules[:deck_size] - chosen_evolutions.size - chosen_specials.size
|
remaining_needed = @rules[:deck_size] - chosen_evolutions.size - chosen_specials.size
|
||||||
|
|
||||||
next if remaining_pool.size < remaining_needed
|
next if remaining_pool.size < remaining_needed
|
||||||
|
|
||||||
chosen_regulars = remaining_pool.sample(remaining_needed)
|
deck = build_deck(
|
||||||
|
chosen_evolutions: chosen_evolutions,
|
||||||
|
chosen_specials: chosen_specials,
|
||||||
|
remaining_pool: remaining_pool
|
||||||
|
)
|
||||||
|
|
||||||
deck = chosen_evolutions + chosen_specials + chosen_regulars
|
next if deck.nil?
|
||||||
next unless valid_deck?(deck)
|
next unless valid_deck?(deck)
|
||||||
|
|
||||||
return deck.shuffle
|
return deck.shuffle
|
||||||
@@ -83,14 +83,89 @@ end
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def build_deck(chosen_evolutions:, chosen_specials:, remaining_pool:)
|
||||||
|
deck = chosen_evolutions + chosen_specials
|
||||||
|
used_names = deck.map(&:name)
|
||||||
|
|
||||||
|
deck = add_required_role_card(deck, remaining_pool, used_names, "spell")
|
||||||
|
return nil if deck.nil?
|
||||||
|
used_names = deck.map(&:name)
|
||||||
|
|
||||||
|
deck = add_required_type_card(deck, remaining_pool, used_names, "troop")
|
||||||
|
return nil if deck.nil?
|
||||||
|
used_names = deck.map(&:name)
|
||||||
|
|
||||||
|
deck = add_required_role_card(deck, remaining_pool, used_names, "win_condition")
|
||||||
|
return nil if deck.nil?
|
||||||
|
used_names = deck.map(&:name)
|
||||||
|
|
||||||
|
deck = add_required_role_card(deck, remaining_pool, used_names, "anti_air")
|
||||||
|
return nil if deck.nil?
|
||||||
|
used_names = deck.map(&:name)
|
||||||
|
|
||||||
|
deck = add_required_meta_cards(deck, remaining_pool, used_names)
|
||||||
|
return nil if deck.nil?
|
||||||
|
used_names = deck.map(&:name)
|
||||||
|
|
||||||
|
cards_left = @rules[:deck_size] - deck.size
|
||||||
|
return nil if cards_left.negative?
|
||||||
|
|
||||||
|
filler_pool = remaining_pool.reject { |card| used_names.include?(card.name) }
|
||||||
|
return nil if filler_pool.size < cards_left
|
||||||
|
|
||||||
|
deck + filler_pool.sample(cards_left)
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_required_role_card(deck, pool, used_names, role)
|
||||||
|
return deck if deck.any? { |card| has_role?(card, role) }
|
||||||
|
|
||||||
|
candidates = pool.select do |card|
|
||||||
|
!used_names.include?(card.name) && has_role?(card, role)
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil if candidates.empty?
|
||||||
|
|
||||||
|
deck + [candidates.sample]
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_required_type_card(deck, pool, used_names, type)
|
||||||
|
return deck if deck.any? { |card| card.type == type }
|
||||||
|
|
||||||
|
candidates = pool.select do |card|
|
||||||
|
!used_names.include?(card.name) && card.type == type
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil if candidates.empty?
|
||||||
|
|
||||||
|
deck + [candidates.sample]
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_required_meta_cards(deck, pool, used_names)
|
||||||
|
current_meta = meta_cards_count(deck)
|
||||||
|
needed_meta = @rules[:min_meta_cards] - current_meta
|
||||||
|
|
||||||
|
return deck if needed_meta <= 0
|
||||||
|
|
||||||
|
meta_candidates = pool.select do |card|
|
||||||
|
!used_names.include?(card.name) && meta_card?(card)
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil if meta_candidates.size < needed_meta
|
||||||
|
|
||||||
|
deck + meta_candidates.sample(needed_meta)
|
||||||
|
end
|
||||||
|
|
||||||
def valid_deck?(deck)
|
def valid_deck?(deck)
|
||||||
return false unless deck.size == @rules[:deck_size]
|
return false unless deck.size == @rules[:deck_size]
|
||||||
return false unless unique_cards?(deck)
|
return false unless unique_cards?(deck)
|
||||||
return false unless enough_spells?(deck)
|
|
||||||
return false unless enough_troops?(deck)
|
return false unless enough_troops?(deck)
|
||||||
return false unless buildings_limit_ok?(deck)
|
return false unless buildings_limit_ok?(deck)
|
||||||
return false unless avg_elixir_ok?(deck)
|
return false unless avg_elixir_ok?(deck)
|
||||||
return false unless special_slots_ok?(deck)
|
return false unless special_slots_ok?(deck)
|
||||||
|
return false unless enough_win_conditions?(deck)
|
||||||
|
return false unless enough_anti_air?(deck)
|
||||||
|
return false unless enough_spell_roles?(deck)
|
||||||
|
return false unless meta_cards_ok?(deck)
|
||||||
|
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
@@ -99,10 +174,6 @@ end
|
|||||||
deck.map(&:name).uniq.size == deck.size
|
deck.map(&:name).uniq.size == deck.size
|
||||||
end
|
end
|
||||||
|
|
||||||
def enough_spells?(deck)
|
|
||||||
deck.count { |card| card.type == "spell" } >= @rules[:min_spells]
|
|
||||||
end
|
|
||||||
|
|
||||||
def enough_troops?(deck)
|
def enough_troops?(deck)
|
||||||
deck.count { |card| card.type == "troop" } >= @rules[:min_troops]
|
deck.count { |card| card.type == "troop" } >= @rules[:min_troops]
|
||||||
end
|
end
|
||||||
@@ -122,6 +193,35 @@ end
|
|||||||
|
|
||||||
[[1, 2], [2, 1]].include?([evolutions_count, special_count])
|
[[1, 2], [2, 1]].include?([evolutions_count, special_count])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def enough_win_conditions?(deck)
|
||||||
|
deck.count { |card| has_role?(card, "win_condition") } >= @rules[:min_win_conditions]
|
||||||
|
end
|
||||||
|
|
||||||
|
def enough_anti_air?(deck)
|
||||||
|
deck.count { |card| has_role?(card, "anti_air") } >= @rules[:min_anti_air]
|
||||||
|
end
|
||||||
|
|
||||||
|
def enough_spell_roles?(deck)
|
||||||
|
deck.count { |card| has_role?(card, "spell") } >= @rules[:min_spell_roles]
|
||||||
|
end
|
||||||
|
|
||||||
|
def meta_cards_ok?(deck)
|
||||||
|
count = meta_cards_count(deck)
|
||||||
|
count >= @rules[:min_meta_cards] && count <= @rules[:max_meta_cards]
|
||||||
|
end
|
||||||
|
|
||||||
|
def meta_cards_count(deck)
|
||||||
|
deck.count { |card| meta_card?(card) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def meta_card?(card)
|
||||||
|
card.is_meta == 1
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_role?(card, role)
|
||||||
|
@roles_repo.has_role?(card.name, role)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
88
app/templates/home/index.html.erb
Normal file
88
app/templates/home/index.html.erb
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
max-width: 960px;
|
||||||
|
margin: 40px auto;
|
||||||
|
padding: 0 16px;
|
||||||
|
background: #111;
|
||||||
|
color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background: #ff6b00;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 12px 18px;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats, .cards {
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
border: 1px solid #333;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 12px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
background: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta {
|
||||||
|
color: #4ade80;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.non-meta {
|
||||||
|
color: #f87171;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.muted {
|
||||||
|
color: #aaa;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<h1>Clash Deck Generator</h1>
|
||||||
|
<p>Generate a deck based on roles, meta cards, and special slot rules.</p>
|
||||||
|
|
||||||
|
<form action="/decks/generate" method="post">
|
||||||
|
<button type="submit">Generate deck</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<% if deck.any? %>
|
||||||
|
<div class="stats">
|
||||||
|
<h2>Deck stats</h2>
|
||||||
|
<p><strong>Average elixir:</strong> <%= stats[:average_elixir] %></p>
|
||||||
|
<p><strong>Meta cards:</strong> <%= stats[:meta_cards_count] %></p>
|
||||||
|
<p><strong>Spells:</strong> <%= stats[:spells_count] %></p>
|
||||||
|
<p><strong>Troops:</strong> <%= stats[:troops_count] %></p>
|
||||||
|
<p><strong>Buildings:</strong> <%= stats[:buildings_count] %></p>
|
||||||
|
<p><strong>Champions:</strong> <%= stats[:champions_count] %></p>
|
||||||
|
<p><strong>Heroes:</strong> <%= stats[:heroes_count] %></p>
|
||||||
|
<p><strong>Evolutions:</strong> <%= stats[:evolutions_count] %></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cards">
|
||||||
|
<h2>Deck cards</h2>
|
||||||
|
|
||||||
|
<% deck.each_with_index do |card, index| %>
|
||||||
|
<% meta_class = card.is_meta == 1 ? "meta" : "non-meta" %>
|
||||||
|
<% meta_text = card.is_meta == 1 ? "META" : "NON-META" %>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div><strong><%= index + 1 %>. <%= card.name %></strong></div>
|
||||||
|
<div class="muted"><%= card.rarity %> | <%= card.type %> | <%= card.elixir_cost %> elixir</div>
|
||||||
|
<div class="<%= meta_class %>"><%= meta_text %></div>
|
||||||
|
<div class="muted">Roles: <%= roles_repo.roles_for(card.name).join(", ") %></div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
@@ -4,11 +4,8 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Clash deck generator2</title>
|
<title>Clash deck generator2</title>
|
||||||
<%= favicon_tag %>
|
|
||||||
<%= stylesheet_tag "app" %>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<%= yield %>
|
<%= yield %>
|
||||||
<%= javascript_tag "app" %>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
13
app/views/home/index.rb
Normal file
13
app/views/home/index.rb
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module ClashDeckGenerator2
|
||||||
|
module Views
|
||||||
|
module Home
|
||||||
|
class Index < ClashDeckGenerator2::View
|
||||||
|
expose :deck, default: []
|
||||||
|
expose :roles_repo
|
||||||
|
expose :stats, default: {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,21 +1,765 @@
|
|||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"description": "Card roles mapping for deck generation"
|
"description": "Card roles mapping for deck generation",
|
||||||
|
"generated_from_db": true,
|
||||||
|
"cards_count": 166,
|
||||||
|
"available_roles": [
|
||||||
|
"anti_air",
|
||||||
|
"building",
|
||||||
|
"building_hate",
|
||||||
|
"control",
|
||||||
|
"cycle",
|
||||||
|
"defense",
|
||||||
|
"finisher",
|
||||||
|
"spell",
|
||||||
|
"splash",
|
||||||
|
"support",
|
||||||
|
"tank",
|
||||||
|
"win_condition"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"cards": {
|
"cards": {
|
||||||
"Knight": ["tank", "defense"],
|
"Archer Queen": [
|
||||||
"Archers": ["support", "anti_air", "cycle"],
|
"support"
|
||||||
"Musketeer": ["support", "anti_air"],
|
],
|
||||||
"Tesla": ["building", "defense", "anti_air"],
|
"Archers": [
|
||||||
"Fireball": ["spell", "splash"],
|
"anti_air",
|
||||||
"Zap": ["spell", "cycle"],
|
"cycle",
|
||||||
"Hog Rider": ["win_condition"],
|
"support"
|
||||||
"Royal Giant": ["win_condition", "tank"],
|
],
|
||||||
"Goblin Barrel": ["win_condition"],
|
"Archers Evolution": [
|
||||||
"Balloon": ["win_condition"],
|
"anti_air",
|
||||||
"Giant": ["win_condition", "tank"],
|
"cycle",
|
||||||
"P.E.K.K.A": ["tank", "defense"],
|
"support"
|
||||||
"Baby Dragon": ["support", "anti_air", "splash"]
|
],
|
||||||
|
"Arrows": [
|
||||||
|
"spell",
|
||||||
|
"splash"
|
||||||
|
],
|
||||||
|
"Baby Dragon": [
|
||||||
|
"anti_air",
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Baby Dragon Evolution": [
|
||||||
|
"anti_air",
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Balloon": [
|
||||||
|
"support",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Bandit": [
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Barbarian Barrel Hero": [
|
||||||
|
"cycle",
|
||||||
|
"defense",
|
||||||
|
"spell"
|
||||||
|
],
|
||||||
|
"Barbarian Hut": [
|
||||||
|
"building",
|
||||||
|
"defense"
|
||||||
|
],
|
||||||
|
"Barbarians": [
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Barbarians Evolution": [
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Bats": [
|
||||||
|
"anti_air",
|
||||||
|
"cycle",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Bats Evolution": [
|
||||||
|
"anti_air",
|
||||||
|
"cycle",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Battle Healer": [
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Battle Ram": [
|
||||||
|
"support",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Battle Ram Evolution": [
|
||||||
|
"support",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Berserker": [
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Bomb Tower": [
|
||||||
|
"building",
|
||||||
|
"defense",
|
||||||
|
"splash"
|
||||||
|
],
|
||||||
|
"Bomber": [
|
||||||
|
"cycle",
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Bomber Evolution": [
|
||||||
|
"cycle",
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Boss Bandit": [
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Bowler": [
|
||||||
|
"defense",
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Cannon": [
|
||||||
|
"building",
|
||||||
|
"defense"
|
||||||
|
],
|
||||||
|
"Cannon Cart": [
|
||||||
|
"defense",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Cannon Evolution": [
|
||||||
|
"building",
|
||||||
|
"defense"
|
||||||
|
],
|
||||||
|
"Clone": [
|
||||||
|
"spell",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Dark Prince": [
|
||||||
|
"splash",
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Dart Goblin": [
|
||||||
|
"anti_air",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Dart Goblin Evolution": [
|
||||||
|
"anti_air",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Earthquake": [
|
||||||
|
"building_hate",
|
||||||
|
"spell"
|
||||||
|
],
|
||||||
|
"Electro Dragon": [
|
||||||
|
"anti_air",
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Electro Dragon Evolution": [
|
||||||
|
"anti_air",
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Electro Giant": [
|
||||||
|
"support",
|
||||||
|
"tank",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Electro Spirit": [
|
||||||
|
"cycle",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Electro Wizard": [
|
||||||
|
"anti_air",
|
||||||
|
"defense",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Elite Barbarians": [
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Elixir Collector": [
|
||||||
|
"building",
|
||||||
|
"defense",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Elixir Golem": [
|
||||||
|
"support",
|
||||||
|
"tank",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Executioner": [
|
||||||
|
"anti_air",
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Executioner Evolution": [
|
||||||
|
"anti_air",
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Fire Spirit": [
|
||||||
|
"cycle",
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Fireball": [
|
||||||
|
"finisher",
|
||||||
|
"spell",
|
||||||
|
"splash"
|
||||||
|
],
|
||||||
|
"Firecracker": [
|
||||||
|
"anti_air",
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Firecracker Evolution": [
|
||||||
|
"anti_air",
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Fisherman": [
|
||||||
|
"control",
|
||||||
|
"defense",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Freeze": [
|
||||||
|
"control",
|
||||||
|
"spell"
|
||||||
|
],
|
||||||
|
"Furnace": [
|
||||||
|
"building",
|
||||||
|
"defense",
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Furnace Evolution": [
|
||||||
|
"building",
|
||||||
|
"defense",
|
||||||
|
"splash"
|
||||||
|
],
|
||||||
|
"Giant": [
|
||||||
|
"support",
|
||||||
|
"tank",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Giant Hero": [
|
||||||
|
"support",
|
||||||
|
"tank",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Giant Skeleton": [
|
||||||
|
"splash",
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Giant Snowball": [
|
||||||
|
"cycle",
|
||||||
|
"spell"
|
||||||
|
],
|
||||||
|
"Giant Snowball Evolution": [
|
||||||
|
"cycle",
|
||||||
|
"spell"
|
||||||
|
],
|
||||||
|
"Goblin Barrel": [
|
||||||
|
"spell",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Goblin Barrel Evolution": [
|
||||||
|
"spell",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Goblin Cage": [
|
||||||
|
"building",
|
||||||
|
"defense"
|
||||||
|
],
|
||||||
|
"Goblin Cage Evolution": [
|
||||||
|
"building",
|
||||||
|
"defense"
|
||||||
|
],
|
||||||
|
"Goblin Demolisher": [
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Goblin Drill": [
|
||||||
|
"building",
|
||||||
|
"support",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Goblin Drill Evolution": [
|
||||||
|
"building",
|
||||||
|
"defense",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Goblin Gang": [
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Goblin Giant": [
|
||||||
|
"support",
|
||||||
|
"tank",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Goblin Giant Evolution": [
|
||||||
|
"support",
|
||||||
|
"tank",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Goblin Giantess": [
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Goblin Hut": [
|
||||||
|
"building",
|
||||||
|
"defense"
|
||||||
|
],
|
||||||
|
"Goblin Machine": [
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Goblins": [
|
||||||
|
"cycle",
|
||||||
|
"defense",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Goblins Hero": [
|
||||||
|
"cycle",
|
||||||
|
"defense",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Goblinstein": [
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Golden Knight": [
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Golem": [
|
||||||
|
"support",
|
||||||
|
"tank",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Graveyard": [
|
||||||
|
"spell",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Guards": [
|
||||||
|
"defense",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Heal Spirit": [
|
||||||
|
"cycle",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Hog Rider": [
|
||||||
|
"support",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Hunter": [
|
||||||
|
"anti_air",
|
||||||
|
"defense",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Hunter Evolution": [
|
||||||
|
"anti_air",
|
||||||
|
"defense",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Ice Golem": [
|
||||||
|
"cycle",
|
||||||
|
"defense",
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Ice Golem Hero": [
|
||||||
|
"cycle",
|
||||||
|
"defense",
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Ice Spirit": [
|
||||||
|
"cycle",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Ice Spirit Evolution": [
|
||||||
|
"cycle",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Ice Wizard": [
|
||||||
|
"defense",
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Inferno Dragon": [
|
||||||
|
"anti_air",
|
||||||
|
"defense",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Inferno Dragon Evolution": [
|
||||||
|
"anti_air",
|
||||||
|
"defense",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Inferno Tower": [
|
||||||
|
"building",
|
||||||
|
"defense"
|
||||||
|
],
|
||||||
|
"Knight": [
|
||||||
|
"defense",
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Knight Evolution": [
|
||||||
|
"defense",
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Knight Hero": [
|
||||||
|
"defense",
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Lava Hound": [
|
||||||
|
"anti_air",
|
||||||
|
"support",
|
||||||
|
"tank",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Lightning": [
|
||||||
|
"finisher",
|
||||||
|
"spell"
|
||||||
|
],
|
||||||
|
"Little Prince": [
|
||||||
|
"anti_air",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Lumberjack": [
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Lumberjack Evolution": [
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Magic Archer": [
|
||||||
|
"anti_air",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Magic Archer Hero": [
|
||||||
|
"anti_air",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Mega Knight": [
|
||||||
|
"defense",
|
||||||
|
"splash",
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Mega Knight Evolution": [
|
||||||
|
"defense",
|
||||||
|
"splash",
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Mega Minion": [
|
||||||
|
"anti_air",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Mega Minion Hero": [
|
||||||
|
"anti_air",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Mighty Miner": [
|
||||||
|
"defense",
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Miner": [
|
||||||
|
"support",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Mini P.E.K.K.A": [
|
||||||
|
"defense",
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Mini P.E.K.K.A Hero": [
|
||||||
|
"defense",
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Minion Horde": [
|
||||||
|
"anti_air",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Minions": [
|
||||||
|
"anti_air",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Mirror": [
|
||||||
|
"spell",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Monk": [
|
||||||
|
"defense",
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Mortar": [
|
||||||
|
"building",
|
||||||
|
"defense",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Mortar Evolution": [
|
||||||
|
"building",
|
||||||
|
"defense",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Mother Witch": [
|
||||||
|
"anti_air",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Musketeer": [
|
||||||
|
"anti_air",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Musketeer Evolution": [
|
||||||
|
"anti_air",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Musketeer Hero": [
|
||||||
|
"anti_air",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Night Witch": [
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"P.E.K.K.A": [
|
||||||
|
"defense",
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"P.E.K.K.A Evolution": [
|
||||||
|
"defense",
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Phoenix": [
|
||||||
|
"anti_air",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Poison": [
|
||||||
|
"finisher",
|
||||||
|
"spell",
|
||||||
|
"splash"
|
||||||
|
],
|
||||||
|
"Prince": [
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Princess": [
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Rage": [
|
||||||
|
"spell",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Ram Rider": [
|
||||||
|
"support",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Rascals": [
|
||||||
|
"anti_air",
|
||||||
|
"defense",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Rocket": [
|
||||||
|
"finisher",
|
||||||
|
"spell"
|
||||||
|
],
|
||||||
|
"Royal Delivery": [
|
||||||
|
"defense",
|
||||||
|
"spell",
|
||||||
|
"splash"
|
||||||
|
],
|
||||||
|
"Royal Ghost": [
|
||||||
|
"splash",
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Royal Ghost Evolution": [
|
||||||
|
"splash",
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Royal Giant": [
|
||||||
|
"support",
|
||||||
|
"tank",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Royal Giant Evolution": [
|
||||||
|
"support",
|
||||||
|
"tank",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Royal Hogs": [
|
||||||
|
"support",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Royal Hogs Evolution": [
|
||||||
|
"support",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Royal Recruits": [
|
||||||
|
"defense",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Royal Recruits Evolution": [
|
||||||
|
"defense",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Skeleton Army": [
|
||||||
|
"defense",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Skeleton Army Evolution": [
|
||||||
|
"defense",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Skeleton Barrel": [
|
||||||
|
"support",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Skeleton Barrel Evolution": [
|
||||||
|
"support",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Skeleton Dragons": [
|
||||||
|
"anti_air",
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Skeleton King": [
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Skeletons": [
|
||||||
|
"cycle",
|
||||||
|
"defense",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Skeletons Evolution": [
|
||||||
|
"cycle",
|
||||||
|
"defense",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Sparky": [
|
||||||
|
"defense",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Spear Goblins": [
|
||||||
|
"cycle",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Spirit Empress": [
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Suspicious Bush": [
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Tesla": [
|
||||||
|
"anti_air",
|
||||||
|
"building",
|
||||||
|
"defense"
|
||||||
|
],
|
||||||
|
"Tesla Evolution": [
|
||||||
|
"anti_air",
|
||||||
|
"building",
|
||||||
|
"defense"
|
||||||
|
],
|
||||||
|
"The Log": [
|
||||||
|
"cycle",
|
||||||
|
"defense",
|
||||||
|
"spell"
|
||||||
|
],
|
||||||
|
"Three Musketeers": [
|
||||||
|
"anti_air",
|
||||||
|
"support",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Tombstone": [
|
||||||
|
"building",
|
||||||
|
"defense"
|
||||||
|
],
|
||||||
|
"Tornado": [
|
||||||
|
"control",
|
||||||
|
"defense",
|
||||||
|
"spell"
|
||||||
|
],
|
||||||
|
"Valkyrie": [
|
||||||
|
"defense",
|
||||||
|
"splash",
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Valkyrie Evolution": [
|
||||||
|
"defense",
|
||||||
|
"splash",
|
||||||
|
"support",
|
||||||
|
"tank"
|
||||||
|
],
|
||||||
|
"Void": [
|
||||||
|
"finisher",
|
||||||
|
"spell"
|
||||||
|
],
|
||||||
|
"Wall Breakers": [
|
||||||
|
"cycle",
|
||||||
|
"support",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Wall Breakers Evolution": [
|
||||||
|
"cycle",
|
||||||
|
"support",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Witch": [
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Witch Evolution": [
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Wizard": [
|
||||||
|
"anti_air",
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Wizard Evolution": [
|
||||||
|
"anti_air",
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"Wizard Hero": [
|
||||||
|
"anti_air",
|
||||||
|
"splash",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"X-Bow": [
|
||||||
|
"building",
|
||||||
|
"defense",
|
||||||
|
"win_condition"
|
||||||
|
],
|
||||||
|
"Zap": [
|
||||||
|
"cycle",
|
||||||
|
"spell"
|
||||||
|
],
|
||||||
|
"Zap Evolution": [
|
||||||
|
"cycle",
|
||||||
|
"spell"
|
||||||
|
],
|
||||||
|
"Zappies": [
|
||||||
|
"anti_air",
|
||||||
|
"defense",
|
||||||
|
"support"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,21 +6,21 @@ EPIC_CARDS = [
|
|||||||
{ name: "Guards", elixir_cost: 3, rarity: "epic", type: "troop", is_meta: 0 },
|
{ name: "Guards", elixir_cost: 3, rarity: "epic", type: "troop", is_meta: 0 },
|
||||||
{ name: "Dark Prince", elixir_cost: 4, rarity: "epic", type: "troop", is_meta: 1 },
|
{ name: "Dark Prince", elixir_cost: 4, rarity: "epic", type: "troop", is_meta: 1 },
|
||||||
{ name: "Hunter", elixir_cost: 4, rarity: "epic", type: "troop", is_meta: 1 },
|
{ name: "Hunter", elixir_cost: 4, rarity: "epic", type: "troop", is_meta: 1 },
|
||||||
{ name: "Baby Dragon", elixir_cost: 4, rarity: "epic", type: "troop", is_meta: 1 },
|
{ name: "Baby Dragon", elixir_cost: 4, rarity: "epic", type: "troop", is_meta: 0 },
|
||||||
{ name: "Goblin Drill", elixir_cost: 4, rarity: "epic", type: "troop", is_meta: 1 },
|
{ name: "Goblin Drill", elixir_cost: 4, rarity: "epic", type: "troop", is_meta: 0 },
|
||||||
{ name: "Prince", elixir_cost: 5, rarity: "epic", type: "troop", is_meta: 1 },
|
{ name: "Prince", elixir_cost: 5, rarity: "epic", type: "troop", is_meta: 0 },
|
||||||
{ name: "Balloon", elixir_cost: 5, rarity: "epic", type: "troop", is_meta: 1 },
|
{ name: "Balloon", elixir_cost: 5, rarity: "epic", type: "troop", is_meta: 1 },
|
||||||
{ name: "Witch", elixir_cost: 5, rarity: "epic", type: "troop", is_meta: 0 },
|
{ name: "Witch", elixir_cost: 5, rarity: "epic", type: "troop", is_meta: 0 },
|
||||||
{ name: "Bowler", elixir_cost: 5, rarity: "epic", type: "troop", is_meta: 0 },
|
{ name: "Bowler", elixir_cost: 5, rarity: "epic", type: "troop", is_meta: 1 },
|
||||||
{ name: "Cannon Cart", elixir_cost: 5, rarity: "epic", type: "troop", is_meta: 0 },
|
{ name: "Cannon Cart", elixir_cost: 5, rarity: "epic", type: "troop", is_meta: 1 },
|
||||||
{ name: "Electro Dragon", elixir_cost: 5, rarity: "epic", type: "troop", is_meta: 0 },
|
{ name: "Electro Dragon", elixir_cost: 5, rarity: "epic", type: "troop", is_meta: 0 },
|
||||||
{ name: "Giant Skeleton", elixir_cost: 6, rarity: "epic", type: "troop", is_meta: 1 },
|
{ name: "Giant Skeleton", elixir_cost: 6, rarity: "epic", type: "troop", is_meta: 1 },
|
||||||
{ name: "Goblin Giant", elixir_cost: 6, rarity: "epic", type: "troop", is_meta: 0 },
|
{ name: "Goblin Giant", elixir_cost: 6, rarity: "epic", type: "troop", is_meta: 0 },
|
||||||
{ name: "P.E.K.K.A", elixir_cost: 7, rarity: "epic", type: "troop", is_meta: 1 },
|
{ name: "P.E.K.K.A", elixir_cost: 7, rarity: "epic", type: "troop", is_meta: 1 },
|
||||||
{ name: "Golem", elixir_cost: 8, rarity: "epic", type: "troop", is_meta: 0 },
|
{ name: "Golem", elixir_cost: 8, rarity: "epic", type: "troop", is_meta: 1 },
|
||||||
{ name: "Electro Giant", elixir_cost: 7, rarity: "epic", type: "troop", is_meta: 0 },
|
{ name: "Electro Giant", elixir_cost: 7, rarity: "epic", type: "troop", is_meta: 0 },
|
||||||
{ name: "Goblin Giantess", elixir_cost: 6, rarity: "epic", type: "troop", is_meta: 0 },
|
{ name: "Goblin Giantess", elixir_cost: 6, rarity: "epic", type: "troop", is_meta: 0 },
|
||||||
{ name: "Skeleton Army", elixir_cost: 3, rarity: "epic", type: "troop", is_meta: 1 },
|
{ name: "Skeleton Army", elixir_cost: 3, rarity: "epic", type: "troop", is_meta: 0 },
|
||||||
{ name: "Executioner", elixir_cost: 5, rarity: "epic", type: "troop", is_meta: 0 },
|
{ name: "Executioner", elixir_cost: 5, rarity: "epic", type: "troop", is_meta: 0 },
|
||||||
|
|
||||||
# Заклинания
|
# Заклинания
|
||||||
@@ -28,12 +28,12 @@ EPIC_CARDS = [
|
|||||||
{ name: "Rage", elixir_cost: 2, rarity: "epic", type: "spell", is_meta: 0 },
|
{ name: "Rage", elixir_cost: 2, rarity: "epic", type: "spell", is_meta: 0 },
|
||||||
{ name: "Clone", elixir_cost: 3, rarity: "epic", type: "spell", is_meta: 0 },
|
{ name: "Clone", elixir_cost: 3, rarity: "epic", type: "spell", is_meta: 0 },
|
||||||
{ name: "Freeze", elixir_cost: 4, rarity: "epic", type: "spell", is_meta: 1 },
|
{ name: "Freeze", elixir_cost: 4, rarity: "epic", type: "spell", is_meta: 1 },
|
||||||
{ name: "Poison", elixir_cost: 4, rarity: "epic", type: "spell", is_meta: 1 },
|
{ name: "Poison", elixir_cost: 4, rarity: "epic", type: "spell", is_meta: 0 },
|
||||||
{ name: "Lightning", elixir_cost: 6, rarity: "epic", type: "spell", is_meta: 0 },
|
{ name: "Lightning", elixir_cost: 6, rarity: "epic", type: "spell", is_meta: 1 },
|
||||||
{ name: "Void", elixir_cost: 3, rarity: "epic", type: "spell", is_meta: 0 },
|
{ name: "Void", elixir_cost: 3, rarity: "epic", type: "spell", is_meta: 0 },
|
||||||
{ name: "Goblin Barrel", elixir_cost: 3, rarity: "epic", type: "spell", is_meta: 1 },
|
{ name: "Goblin Barrel", elixir_cost: 3, rarity: "epic", type: "spell", is_meta: 0 },
|
||||||
{ name: "Tornado", elixir_cost: 3, rarity: "epic", type: "spell", is_meta: 1 },
|
{ name: "Tornado", elixir_cost: 3, rarity: "epic", type: "spell", is_meta: 1 },
|
||||||
|
|
||||||
# Здания
|
# Здания
|
||||||
{ name: "X-Bow", elixir_cost: 6, rarity: "epic", type: "building", is_meta: 0 }
|
{ name: "X-Bow", elixir_cost: 6, rarity: "epic", type: "building", is_meta: 1 }
|
||||||
].freeze
|
].freeze
|
||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
HERO_CARDS = [
|
HERO_CARDS = [
|
||||||
{ name: "Goblins Hero", elixir_cost: 2, rarity: "hero", type: "troop", is_meta: 1 },
|
{ name: "Goblins Hero", elixir_cost: 2, rarity: "hero", type: "troop", is_meta: 1 },
|
||||||
{ name: "Knight Hero", elixir_cost: 3, rarity: "hero", type: "troop", is_meta: 1 },
|
{ name: "Knight Hero", elixir_cost: 3, rarity: "hero", type: "troop", is_meta: 0 },
|
||||||
{ name: "Ice Golem Hero", elixir_cost: 2, rarity: "hero", type: "troop", is_meta: 0 },
|
{ name: "Ice Golem Hero", elixir_cost: 2, rarity: "hero", type: "troop", is_meta: 0 },
|
||||||
{ name: "Mega Minion Hero", elixir_cost: 3, rarity: "hero", type: "troop", is_meta: 0 },
|
{ name: "Mega Minion Hero", elixir_cost: 3, rarity: "hero", type: "troop", is_meta: 1 },
|
||||||
{ name: "Mini P.E.K.K.A Hero", elixir_cost: 4, rarity: "hero", type: "troop", is_meta: 1 },
|
{ name: "Mini P.E.K.K.A Hero", elixir_cost: 4, rarity: "hero", type: "troop", is_meta: 0 },
|
||||||
{ name: "Musketeer Hero", elixir_cost: 4, rarity: "hero", type: "troop", is_meta: 1 },
|
{ name: "Musketeer Hero", elixir_cost: 4, rarity: "hero", type: "troop", is_meta: 0 },
|
||||||
{ name: "Giant Hero", elixir_cost: 5, rarity: "hero", type: "troop", is_meta: 0 },
|
{ name: "Giant Hero", elixir_cost: 5, rarity: "hero", type: "troop", is_meta: 1 },
|
||||||
{ name: "Wizard Hero", elixir_cost: 5, rarity: "hero", type: "troop", is_meta: 0 },
|
{ name: "Wizard Hero", elixir_cost: 5, rarity: "hero", type: "troop", is_meta: 0 },
|
||||||
{ name: "Barbarian Barrel Hero", elixir_cost: 2, rarity: "hero", type: "spell", is_meta: 1 },
|
{ name: "Barbarian Barrel Hero", elixir_cost: 2, rarity: "hero", type: "spell", is_meta: 1 },
|
||||||
{ name: "Magic Archer Hero", elixir_cost: 4, rarity: "hero", type: "troop", is_meta: 1 }
|
{ name: "Magic Archer Hero", elixir_cost: 4, rarity: "hero", type: "troop", is_meta: 1 }
|
||||||
|
|||||||
@@ -2,27 +2,27 @@
|
|||||||
|
|
||||||
LEGENDARY_CARDS = [
|
LEGENDARY_CARDS = [
|
||||||
# Юниты
|
# Юниты
|
||||||
{ name: "Miner", elixir_cost: 3, rarity: "legendary", type: "troop", is_meta: 1 },
|
{ name: "Miner", elixir_cost: 3, rarity: "legendary", type: "troop", is_meta: 0 },
|
||||||
{ name: "Princess", elixir_cost: 3, rarity: "legendary", type: "troop", is_meta: 1 },
|
{ name: "Princess", elixir_cost: 3, rarity: "legendary", type: "troop", is_meta: 0 },
|
||||||
{ name: "Ice Wizard", elixir_cost: 3, rarity: "legendary", type: "troop", is_meta: 0 },
|
{ name: "Ice Wizard", elixir_cost: 3, rarity: "legendary", type: "troop", is_meta: 0 },
|
||||||
{ name: "Royal Ghost", elixir_cost: 3, rarity: "legendary", type: "troop", is_meta: 1 },
|
{ name: "Royal Ghost", elixir_cost: 3, rarity: "legendary", type: "troop", is_meta: 0 },
|
||||||
{ name: "Bandit", elixir_cost: 3, rarity: "legendary", type: "troop", is_meta: 1 },
|
{ name: "Bandit", elixir_cost: 3, rarity: "legendary", type: "troop", is_meta: 1 },
|
||||||
{ name: "Fisherman", elixir_cost: 3, rarity: "legendary", type: "troop", is_meta: 0 },
|
{ name: "Fisherman", elixir_cost: 3, rarity: "legendary", type: "troop", is_meta: 1 },
|
||||||
{ name: "Electro Wizard", elixir_cost: 4, rarity: "legendary", type: "troop", is_meta: 1 },
|
{ name: "Electro Wizard", elixir_cost: 4, rarity: "legendary", type: "troop", is_meta: 1 },
|
||||||
{ name: "Inferno Dragon", elixir_cost: 4, rarity: "legendary", type: "troop", is_meta: 1 },
|
{ name: "Inferno Dragon", elixir_cost: 4, rarity: "legendary", type: "troop", is_meta: 0 },
|
||||||
{ name: "Phoenix", elixir_cost: 4, rarity: "legendary", type: "troop", is_meta: 1 },
|
{ name: "Phoenix", elixir_cost: 4, rarity: "legendary", type: "troop", is_meta: 1 },
|
||||||
{ name: "Magic Archer", elixir_cost: 4, rarity: "legendary", type: "troop", is_meta: 1 },
|
{ name: "Magic Archer", elixir_cost: 4, rarity: "legendary", type: "troop", is_meta: 0 },
|
||||||
{ name: "Lumberjack", elixir_cost: 4, rarity: "legendary", type: "troop", is_meta: 1 },
|
{ name: "Lumberjack", elixir_cost: 4, rarity: "legendary", type: "troop", is_meta: 0 },
|
||||||
{ name: "Night Witch", elixir_cost: 4, rarity: "legendary", type: "troop", is_meta: 0 },
|
{ name: "Night Witch", elixir_cost: 4, rarity: "legendary", type: "troop", is_meta: 1 },
|
||||||
{ name: "Mother Witch", elixir_cost: 4, rarity: "legendary", type: "troop", is_meta: 0 },
|
{ name: "Mother Witch", elixir_cost: 4, rarity: "legendary", type: "troop", is_meta: 1 },
|
||||||
{ name: "Ram Rider", elixir_cost: 5, rarity: "legendary", type: "troop", is_meta: 0 },
|
{ name: "Ram Rider", elixir_cost: 5, rarity: "legendary", type: "troop", is_meta: 0 },
|
||||||
{ name: "Goblin Machine", elixir_cost: 5, rarity: "legendary", type: "troop", is_meta: 0 },
|
{ name: "Goblin Machine", elixir_cost: 5, rarity: "legendary", type: "troop", is_meta: 0 },
|
||||||
{ name: "Sparky", elixir_cost: 6, rarity: "legendary", type: "troop", is_meta: 0 },
|
{ name: "Sparky", elixir_cost: 6, rarity: "legendary", type: "troop", is_meta: 0 },
|
||||||
{ name: "Spirit Empress", elixir_cost: 6, rarity: "legendary", type: "troop", is_meta: 0 },
|
{ name: "Spirit Empress", elixir_cost: 6, rarity: "legendary", type: "troop", is_meta: 1 },
|
||||||
{ name: "Mega Knight", elixir_cost: 7, rarity: "legendary", type: "troop", is_meta: 1 },
|
{ name: "Mega Knight", elixir_cost: 7, rarity: "legendary", type: "troop", is_meta: 0 },
|
||||||
{ name: "Lava Hound", elixir_cost: 7, rarity: "legendary", type: "troop", is_meta: 0 },
|
{ name: "Lava Hound", elixir_cost: 7, rarity: "legendary", type: "troop", is_meta: 1 },
|
||||||
|
|
||||||
# Заклинания
|
# Заклинания
|
||||||
{ name: "The Log", elixir_cost: 2, rarity: "legendary", type: "spell", is_meta: 1 },
|
{ name: "The Log", elixir_cost: 2, rarity: "legendary", type: "spell", is_meta: 0 },
|
||||||
{ name: "Graveyard", elixir_cost: 5, rarity: "legendary", type: "spell", is_meta: 1 }
|
{ name: "Graveyard", elixir_cost: 5, rarity: "legendary", type: "spell", is_meta: 1 }
|
||||||
].freeze
|
].freeze
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
module ClashDeckGenerator2
|
module ClashDeckGenerator2
|
||||||
class Routes < Hanami::Routes
|
class Routes < Hanami::Routes
|
||||||
# Add your routes here. See https://guides.hanamirb.org/routing/overview/ for details.
|
root to: "home.index"
|
||||||
|
post "/decks/generate", to: "decks.generate"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
257
script/build_roles_json.rb
Normal file
257
script/build_roles_json.rb
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "json"
|
||||||
|
require_relative "../config/app"
|
||||||
|
|
||||||
|
Hanami.app.prepare
|
||||||
|
|
||||||
|
module ClashDeckGenerator2
|
||||||
|
module Scripts
|
||||||
|
class BuildRolesJson
|
||||||
|
OUTPUT_PATH = File.expand_path("../config/cards/roles.json", __dir__)
|
||||||
|
|
||||||
|
BASE_ROLES_BY_TYPE = {
|
||||||
|
"spell" => %w[spell],
|
||||||
|
"building" => %w[building defense],
|
||||||
|
"troop" => %w[support]
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
ROLE_OVERRIDES = {
|
||||||
|
# cycle
|
||||||
|
"Skeletons" => %w[cycle defense],
|
||||||
|
"Ice Spirit" => %w[cycle support],
|
||||||
|
"Electro Spirit" => %w[cycle support],
|
||||||
|
"Fire Spirit" => %w[cycle support splash],
|
||||||
|
"Heal Spirit" => %w[cycle support],
|
||||||
|
"Goblins" => %w[cycle defense],
|
||||||
|
"Spear Goblins" => %w[cycle support],
|
||||||
|
"Bats" => %w[cycle anti_air],
|
||||||
|
"Wall Breakers" => %w[cycle win_condition],
|
||||||
|
"Bomber" => %w[cycle splash support],
|
||||||
|
|
||||||
|
# win conditions
|
||||||
|
"Hog Rider" => %w[win_condition],
|
||||||
|
"Royal Giant" => %w[win_condition tank],
|
||||||
|
"Goblin Barrel" => %w[win_condition],
|
||||||
|
"Balloon" => %w[win_condition],
|
||||||
|
"Giant" => %w[win_condition tank],
|
||||||
|
"Golem" => %w[win_condition tank],
|
||||||
|
"Electro Giant" => %w[win_condition tank],
|
||||||
|
"Goblin Drill" => %w[win_condition],
|
||||||
|
"X-Bow" => %w[win_condition building defense],
|
||||||
|
"Mortar" => %w[win_condition building defense],
|
||||||
|
"Ram Rider" => %w[win_condition support],
|
||||||
|
"Graveyard" => %w[win_condition spell],
|
||||||
|
"Royal Hogs" => %w[win_condition],
|
||||||
|
"Battle Ram" => %w[win_condition],
|
||||||
|
"Elixir Golem" => %w[win_condition tank],
|
||||||
|
"Lava Hound" => %w[win_condition tank anti_air],
|
||||||
|
"Goblin Barrel" => %w[win_condition],
|
||||||
|
"Goblin Drill" => %w[win_condition building],
|
||||||
|
"Miner" => %w[win_condition support],
|
||||||
|
"Goblin Giant" => %w[win_condition tank],
|
||||||
|
"Three Musketeers" => %w[win_condition support anti_air],
|
||||||
|
"Skeleton Barrel" => %w[win_condition],
|
||||||
|
"Rocket" => %w[spell finisher],
|
||||||
|
"Fireball" => %w[spell finisher splash],
|
||||||
|
"Poison" => %w[spell finisher splash],
|
||||||
|
"Lightning" => %w[spell finisher],
|
||||||
|
"Void" => %w[spell finisher],
|
||||||
|
|
||||||
|
# anti air
|
||||||
|
"Archers" => %w[anti_air support cycle],
|
||||||
|
"Musketeer" => %w[anti_air support],
|
||||||
|
"Wizard" => %w[anti_air support splash],
|
||||||
|
"Baby Dragon" => %w[anti_air support splash],
|
||||||
|
"Electro Dragon" => %w[anti_air support splash],
|
||||||
|
"Inferno Dragon" => %w[anti_air defense],
|
||||||
|
"Mega Minion" => %w[anti_air support],
|
||||||
|
"Flying Machine" => %w[anti_air support],
|
||||||
|
"Hunter" => %w[anti_air defense],
|
||||||
|
"Firecracker" => %w[anti_air support splash],
|
||||||
|
"Minions" => %w[anti_air support],
|
||||||
|
"Minion Horde" => %w[anti_air support],
|
||||||
|
"Skeleton Dragons" => %w[anti_air support splash],
|
||||||
|
"Phoenix" => %w[anti_air support],
|
||||||
|
"Executioner" => %w[anti_air support splash],
|
||||||
|
"Tesla" => %w[anti_air building defense],
|
||||||
|
"Inferno Tower" => %w[building defense],
|
||||||
|
"Magic Archer" => %w[support anti_air],
|
||||||
|
"Zappies" => %w[support anti_air defense],
|
||||||
|
"Dart Goblin" => %w[support anti_air],
|
||||||
|
"Electro Wizard" => %w[support anti_air defense],
|
||||||
|
"Mother Witch" => %w[support anti_air],
|
||||||
|
"Little Prince" => %w[support anti_air],
|
||||||
|
|
||||||
|
# tanks / mini tanks
|
||||||
|
"Knight" => %w[tank defense],
|
||||||
|
"Valkyrie" => %w[tank defense splash],
|
||||||
|
"Ice Golem" => %w[tank cycle defense],
|
||||||
|
"P.E.K.K.A" => %w[tank defense],
|
||||||
|
"Mini P.E.K.K.A" => %w[defense tank],
|
||||||
|
"Mega Knight" => %w[tank defense splash],
|
||||||
|
"Royal Ghost" => %w[tank support splash],
|
||||||
|
"Dark Prince" => %w[tank support splash],
|
||||||
|
"Prince" => %w[tank support],
|
||||||
|
"Skeleton King" => %w[tank support],
|
||||||
|
"Golden Knight" => %w[tank support],
|
||||||
|
"Monk" => %w[tank defense],
|
||||||
|
"Mighty Miner" => %w[defense tank],
|
||||||
|
"Giant Skeleton" => %w[tank splash],
|
||||||
|
"Lumberjack" => %w[support tank],
|
||||||
|
"Bandit" => %w[support],
|
||||||
|
"Battle Healer" => %w[support tank],
|
||||||
|
"Goblin Giantess" => %w[tank support],
|
||||||
|
|
||||||
|
# buildings / defense
|
||||||
|
"Cannon" => %w[building defense],
|
||||||
|
"Tesla" => %w[building defense anti_air],
|
||||||
|
"Bomb Tower" => %w[building defense splash],
|
||||||
|
"Tombstone" => %w[building defense],
|
||||||
|
"Goblin Cage" => %w[building defense],
|
||||||
|
"Goblin Hut" => %w[building defense],
|
||||||
|
"Barbarian Hut" => %w[building defense],
|
||||||
|
"Furnace" => %w[building defense splash],
|
||||||
|
"Elixir Collector" => %w[building support],
|
||||||
|
"Goblin Drill" => %w[building win_condition],
|
||||||
|
"X-Bow" => %w[building win_condition defense],
|
||||||
|
"Mortar" => %w[building win_condition defense],
|
||||||
|
|
||||||
|
# splash / control
|
||||||
|
"Bowler" => %w[splash support defense],
|
||||||
|
"Witch" => %w[support splash],
|
||||||
|
"Bomber" => %w[support splash cycle],
|
||||||
|
"Arrows" => %w[spell splash],
|
||||||
|
"Zap" => %w[spell cycle],
|
||||||
|
"Giant Snowball" => %w[spell cycle],
|
||||||
|
"Royal Delivery" => %w[spell defense splash],
|
||||||
|
"Tornado" => %w[spell control defense],
|
||||||
|
"Rage" => %w[spell support],
|
||||||
|
"Freeze" => %w[spell control],
|
||||||
|
"Clone" => %w[spell support],
|
||||||
|
"Mirror" => %w[spell support],
|
||||||
|
"Earthquake" => %w[spell building_hate],
|
||||||
|
"The Log" => %w[spell cycle defense],
|
||||||
|
"Barbarian Barrel" => %w[spell cycle defense],
|
||||||
|
|
||||||
|
# support / utility
|
||||||
|
"Skeleton Army" => %w[defense],
|
||||||
|
"Guards" => %w[defense],
|
||||||
|
"Royal Recruits" => %w[defense],
|
||||||
|
"Rascals" => %w[defense support anti_air],
|
||||||
|
"Cannon Cart" => %w[support defense],
|
||||||
|
"Sparky" => %w[support defense],
|
||||||
|
"Night Witch" => %w[support],
|
||||||
|
"Princess" => %w[support splash],
|
||||||
|
"Ice Wizard" => %w[support defense splash],
|
||||||
|
"Fisherman" => %w[defense control],
|
||||||
|
"Goblin Demolisher" => %w[support splash],
|
||||||
|
"Suspicious Bush" => %w[support],
|
||||||
|
"Battle Ram" => %w[win_condition],
|
||||||
|
"Royal Hogs" => %w[win_condition],
|
||||||
|
"Royal Recruits" => %w[defense],
|
||||||
|
"Electro Giant" => %w[win_condition tank],
|
||||||
|
"Electro Dragon" => %w[anti_air support splash],
|
||||||
|
"Goblin Machine" => %w[support],
|
||||||
|
"Spirit Empress" => %w[support],
|
||||||
|
"Boss Bandit" => %w[support],
|
||||||
|
"Goblins" => %w[cycle defense]
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
def call
|
||||||
|
repo = ClashDeckGenerator2::Repos::CardsRepo.new
|
||||||
|
cards = unwrap(repo.all)
|
||||||
|
|
||||||
|
cards_by_name = {}
|
||||||
|
cards.each do |card|
|
||||||
|
cards_by_name[card.name] ||= card
|
||||||
|
end
|
||||||
|
|
||||||
|
result = {
|
||||||
|
"_meta" => {
|
||||||
|
"version" => 1,
|
||||||
|
"description" => "Card roles mapping for deck generation",
|
||||||
|
"generated_from_db" => true,
|
||||||
|
"cards_count" => cards_by_name.size,
|
||||||
|
"available_roles" => available_roles
|
||||||
|
},
|
||||||
|
"cards" => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
cards_by_name.keys.sort.each do |card_name|
|
||||||
|
card = cards_by_name[card_name]
|
||||||
|
roles = roles_for(card)
|
||||||
|
result["cards"][card_name] = roles
|
||||||
|
end
|
||||||
|
|
||||||
|
FileUtils.mkdir_p(File.dirname(OUTPUT_PATH))
|
||||||
|
File.write(OUTPUT_PATH, JSON.pretty_generate(result))
|
||||||
|
|
||||||
|
puts "roles.json generated: #{OUTPUT_PATH}"
|
||||||
|
puts "Unique cards exported: #{cards_by_name.size}"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def unwrap(result)
|
||||||
|
if result.is_a?(Array) && result.first == :cards
|
||||||
|
result.last
|
||||||
|
else
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def roles_for(card)
|
||||||
|
roles = []
|
||||||
|
roles.concat(BASE_ROLES_BY_TYPE.fetch(card.type, []))
|
||||||
|
|
||||||
|
base_name = base_card_name(card.name)
|
||||||
|
override_roles = ROLE_OVERRIDES[card.name] || ROLE_OVERRIDES[base_name] || []
|
||||||
|
roles.concat(override_roles)
|
||||||
|
|
||||||
|
roles = roles.map(&:to_s).map(&:strip).reject(&:empty?).uniq.sort
|
||||||
|
|
||||||
|
roles = fallback_roles(card) if roles.empty?
|
||||||
|
roles
|
||||||
|
end
|
||||||
|
|
||||||
|
def base_card_name(name)
|
||||||
|
name
|
||||||
|
.sub(/ Evolution\z/, "")
|
||||||
|
.sub(/ Hero\z/, "")
|
||||||
|
end
|
||||||
|
|
||||||
|
def fallback_roles(card)
|
||||||
|
case card.type
|
||||||
|
when "spell"
|
||||||
|
["spell"]
|
||||||
|
when "building"
|
||||||
|
%w[building defense]
|
||||||
|
when "troop"
|
||||||
|
["support"]
|
||||||
|
else
|
||||||
|
["support"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def available_roles
|
||||||
|
%w[
|
||||||
|
anti_air
|
||||||
|
building
|
||||||
|
building_hate
|
||||||
|
control
|
||||||
|
cycle
|
||||||
|
defense
|
||||||
|
finisher
|
||||||
|
spell
|
||||||
|
splash
|
||||||
|
support
|
||||||
|
tank
|
||||||
|
win_condition
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ClashDeckGenerator2::Scripts::BuildRolesJson.new.call
|
||||||
@@ -4,40 +4,14 @@ require_relative "../config/app"
|
|||||||
|
|
||||||
Hanami.app.prepare
|
Hanami.app.prepare
|
||||||
|
|
||||||
|
repo = ClashDeckGenerator2::Repos::CardsRepo.new
|
||||||
roles_repo = ClashDeckGenerator2::Services::CardRolesRepository.new
|
roles_repo = ClashDeckGenerator2::Services::CardRolesRepository.new
|
||||||
|
generator = ClashDeckGenerator2::Services::DeckGenerator.new(
|
||||||
|
cards_repo: repo,
|
||||||
|
roles_repo: roles_repo
|
||||||
|
)
|
||||||
|
|
||||||
puts roles_repo.roles_for("Knight").inspect
|
|
||||||
puts roles_repo.roles_for("Hog Rider").inspect
|
|
||||||
puts roles_repo.has_role?("Hog Rider", "win_condition")
|
|
||||||
puts roles_repo.has_role?("Tesla", "win_condition")
|
|
||||||
puts roles_repo.meta.inspect
|
|
||||||
|
|
||||||
cards = repo.all
|
|
||||||
cards = cards.last if cards.is_a?(Array) && cards.first == :cards
|
|
||||||
|
|
||||||
rarity_counts = cards.group_by(&:rarity).transform_values(&:size)
|
|
||||||
|
|
||||||
puts "RARITY COUNTS:"
|
|
||||||
rarity_counts.each do |rarity, count|
|
|
||||||
puts "#{rarity}: #{count}"
|
|
||||||
end
|
|
||||||
|
|
||||||
puts "========================================"
|
|
||||||
puts "POOL DIAGNOSTICS"
|
|
||||||
puts "========================================"
|
|
||||||
puts "Total cards: #{cards.size}"
|
|
||||||
puts "Spells: #{cards.count { |c| c.type == 'spell' }}"
|
|
||||||
puts "Troops: #{cards.count { |c| c.type == 'troop' }}"
|
|
||||||
puts "Buildings: #{cards.count { |c| c.type == 'building' }}"
|
|
||||||
puts "Champions: #{cards.count { |c| c.rarity == 'champion' }}"
|
|
||||||
puts "Heroes: #{cards.count { |c| c.rarity == 'hero' }}"
|
|
||||||
puts "Evolutions: #{cards.count { |c| c.rarity == 'evolution' }}"
|
|
||||||
puts "Avg elixir all cards: #{(cards.sum(&:elixir_cost).to_f / cards.size).round(2)}"
|
|
||||||
puts "========================================"
|
|
||||||
|
|
||||||
generator = ClashDeckGenerator2::Services::DeckGenerator.new(cards_repo: repo)
|
|
||||||
deck = generator.call
|
deck = generator.call
|
||||||
|
|
||||||
deck = deck.last if deck.is_a?(Array) && deck.first == :cards
|
deck = deck.last if deck.is_a?(Array) && deck.first == :cards
|
||||||
|
|
||||||
puts "========================================"
|
puts "========================================"
|
||||||
@@ -45,7 +19,11 @@ puts "DECK GENERATED SUCCESSFULLY"
|
|||||||
puts "========================================"
|
puts "========================================"
|
||||||
|
|
||||||
deck.each_with_index do |card, index|
|
deck.each_with_index do |card, index|
|
||||||
puts "#{index + 1}. #{card.name} | #{card.type} | #{card.rarity} | #{card.elixir_cost}"
|
roles = roles_repo.roles_for(card.name)
|
||||||
|
meta_flag = card.is_meta == 1 ? "META" : "NON-META"
|
||||||
|
|
||||||
|
puts "#{index + 1}. #{card.name} | #{card.type} | #{card.rarity} | #{card.elixir_cost} | #{meta_flag}"
|
||||||
|
puts " roles: #{roles.join(', ')}"
|
||||||
end
|
end
|
||||||
|
|
||||||
puts "----------------------------------------"
|
puts "----------------------------------------"
|
||||||
@@ -56,10 +34,18 @@ puts "Unique cards count: #{names.uniq.size}"
|
|||||||
|
|
||||||
avg_elixir = deck.sum(&:elixir_cost).to_f / deck.size
|
avg_elixir = deck.sum(&:elixir_cost).to_f / deck.size
|
||||||
puts "Average elixir: #{avg_elixir.round(2)}"
|
puts "Average elixir: #{avg_elixir.round(2)}"
|
||||||
puts "Spells count: #{deck.count { |c| c.type == 'spell' }}"
|
puts "Spells by type: #{deck.count { |c| c.type == 'spell' }}"
|
||||||
puts "Troops count: #{deck.count { |c| c.type == 'troop' }}"
|
puts "Troops count: #{deck.count { |c| c.type == 'troop' }}"
|
||||||
puts "Buildings count: #{deck.count { |c| c.type == 'building' }}"
|
puts "Buildings count: #{deck.count { |c| c.type == 'building' }}"
|
||||||
puts "Champions count: #{deck.count { |c| c.rarity == 'champion' }}"
|
puts "Champions count: #{deck.count { |c| c.rarity == 'champion' }}"
|
||||||
puts "Heroes count: #{deck.count { |c| c.rarity == 'hero' }}"
|
puts "Heroes count: #{deck.count { |c| c.rarity == 'hero' }}"
|
||||||
puts "Evolutions count: #{deck.count { |c| c.rarity == 'evolution' }}"
|
puts "Evolutions count: #{deck.count { |c| c.rarity == 'evolution' }}"
|
||||||
|
puts "Meta cards count: #{deck.count { |c| c.is_meta == 1 }}"
|
||||||
|
|
||||||
|
all_roles = deck.flat_map { |card| roles_repo.roles_for(card.name) }.uniq.sort
|
||||||
|
puts "Deck roles coverage: #{all_roles.join(', ')}"
|
||||||
|
|
||||||
|
puts "Win conditions count: #{deck.count { |c| roles_repo.has_role?(c.name, 'win_condition') }}"
|
||||||
|
puts "Anti-air count: #{deck.count { |c| roles_repo.has_role?(c.name, 'anti_air') }}"
|
||||||
|
puts "Spell-role count: #{deck.count { |c| roles_repo.has_role?(c.name, 'spell') }}"
|
||||||
puts "========================================"
|
puts "========================================"
|
||||||
Reference in New Issue
Block a user