Oops, fix modeling logic
Oh huh, I guess most of the new items we had when I rewrote this were Maraquan, and I didn't test enough on standard species-specific items. Before this change, partially-modeled items for standard pets would appear as fully modeled, because the presence of the "nonstandard" color Orange (because of the Orange Chia) meant that the "standard" key didn't actually have any unique bodies (it was all `["standard", 47]`). Here, I take my own comments' advice and move away from the standard label as part of the logic. Instead, we look first for nonstandard colors with unique bodies, which we'll call out as modelable; and then check whether there are any basic bodies *not* covered by those special colors. That way, compatibility with the Maraquan Acara (a unique body) means we'll treat Maraquan as a modelable color; and then we'll ignore the basic bodies, even though it *does* fit the basic Mynci, because there aren't any compatible basic bodies that aren't *also* Maraquan bodies. This also means that compatibility with both the Blue Acara and Orange Acara does *not* preclude a normal item from needing basic pets for models: because, while Orange is a slightly nonstandard color in the case of Chia, it doesn't have its own unique body for this item, so we ignore it when predicting compatibility with basic colors.
This commit is contained in:
parent
13a0362e6d
commit
71f0aa4908
1 changed files with 27 additions and 29 deletions
|
@ -291,43 +291,41 @@ class Item < ApplicationRecord
|
||||||
compatible_body_ids
|
compatible_body_ids
|
||||||
else
|
else
|
||||||
# First, find our compatible pet types, then pair each body ID with its
|
# First, find our compatible pet types, then pair each body ID with its
|
||||||
# color. (We de-dupe standard colors into the key "standard", but it's
|
# color. (As an optimization, we omit standard colors, other than the
|
||||||
# still possible that a body might appear multiple times in this list,
|
# basic colors. We also flatten the basic colors into the single color
|
||||||
# e.g. the Maraquan Mynci's body matches the standard Mynci body.)
|
# ID "basic", so we can treat them specially.)
|
||||||
#
|
compatible_pairs = compatible_pet_types.joins(:color).
|
||||||
# TODO: I feel like the more robust way to do this would be to flatten to
|
merge(Color.nonstandard.or(Color.basic)).
|
||||||
# whatever matches the colors labeled "basic", rather than
|
distinct.pluck(
|
||||||
# "standard", because that's a much more reliable label in our data.
|
Arel.sql("IF(colors.basic, 'basic', colors.id)"), :body_id)
|
||||||
# But that's not as easy to formulate a query about; moving on!
|
|
||||||
compatible_pairs = compatible_pet_types.joins(:color).distinct.
|
|
||||||
pluck(Arel.sql('IF(colors.standard, "standard", colors.id)'), :body_id)
|
|
||||||
|
|
||||||
# Look for colors that have compatible bodies that no other colors have.
|
# Group colors by body, to help us find bodies unique to certain colors.
|
||||||
# We do this by doing the converse: look for bodies with only one color.
|
|
||||||
# (This helps us e.g. ignore the Maraquan Mynci throwing things off!)
|
|
||||||
compatible_color_ids_by_body_id = {}.tap do |h|
|
compatible_color_ids_by_body_id = {}.tap do |h|
|
||||||
compatible_pairs.each do |(color_id, body_id)|
|
compatible_pairs.each do |(color_id, body_id)|
|
||||||
h[body_id] ||= []
|
h[body_id] ||= []
|
||||||
h[body_id] << color_id
|
h[body_id] << color_id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
modelable_color_ids = compatible_color_ids_by_body_id.
|
|
||||||
filter { |k, v| v.size == 1 }.values.map(&:first).uniq
|
|
||||||
|
|
||||||
# Get all body IDs for the colors we decided are modelable: look up all
|
# Find non-basic colors with at least one unique compatible body. (This
|
||||||
# matching pet types, and get their distinct body IDs.
|
# means we'll ignore e.g. the Maraquan Mynci, which has the same body as
|
||||||
conditions = modelable_color_ids.map do |color_id|
|
# the Blue Mynci, as not indicating Maraquan compatibility in general.)
|
||||||
if color_id == "standard"
|
modelable_color_ids =
|
||||||
# Perhaps surprisingly, we filter to basic rather than standard
|
compatible_color_ids_by_body_id.
|
||||||
# colors here, to reduce the risk of getting unexpected bodies swept
|
filter { |k, v| v.size == 1 && v.first != "basic" }.
|
||||||
# up in the mix. (e.g. the Chia is sometimes weird on
|
values.map(&:first).uniq
|
||||||
# otherwise-standard colors)
|
|
||||||
PetType.where(color: {basic: true})
|
# We can model on basic pets (perhaps in addition to the above) if we
|
||||||
else
|
# find at least one compatible basic body that doesn't *also* fit any of
|
||||||
PetType.where(color_id:)
|
# the modelable colors we identified above.
|
||||||
end
|
basic_is_modelable =
|
||||||
end
|
compatible_color_ids_by_body_id.values.
|
||||||
predicted_pet_types = conditions.inject(PetType.none, &:or).joins(:color)
|
any? { |v| v.include?("basic") && (v & modelable_color_ids).empty? }
|
||||||
|
|
||||||
|
# Get all body IDs for the colors we decided are modelable.
|
||||||
|
predicted_pet_types =
|
||||||
|
(basic_is_modelable ? PetType.basic : PetType.none).
|
||||||
|
or(PetType.where(color_id: modelable_color_ids))
|
||||||
predicted_pet_types.distinct.pluck(:body_id).sort
|
predicted_pet_types.distinct.pluck(:body_id).sort
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue