feat: Implement support for Segmented Ribcage
Segmented Ribcages may be used in several unique ways, including a special scaling cost that necessitated the bulk of the code changes.
This commit is contained in:
commit
92e734d5d2
|
@ -19,6 +19,17 @@ class Appendage(Enum):
|
||||||
amalgamy = 2
|
amalgamy = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Cost from this scales with segments and is partially implemented separately
|
||||||
|
# Requires Torso Style 110
|
||||||
|
# Requires initial tail slot
|
||||||
|
SEGMENTED_RIBCAGE = Action(
|
||||||
|
"Extend the tail end with another Segmented Ribcage",
|
||||||
|
cost = Cost.ACTION.value + Cost.SEGMENTED_RIBCAGE.value,
|
||||||
|
value = 250,
|
||||||
|
limbs_needed = 2,
|
||||||
|
segments = 1
|
||||||
|
)
|
||||||
|
|
||||||
ALBATROSS_WING = Action(
|
ALBATROSS_WING = Action(
|
||||||
"Put an Albatross Wing on your (Skeleton Type)",
|
"Put an Albatross Wing on your (Skeleton Type)",
|
||||||
cost = Cost.ACTION.value + Cost.ALBATROSS_WING.value,
|
cost = Cost.ACTION.value + Cost.ALBATROSS_WING.value,
|
||||||
|
|
|
@ -184,6 +184,10 @@ class Cost(Enum):
|
||||||
# Khan's Heart, disgruntled academic
|
# Khan's Heart, disgruntled academic
|
||||||
SEARING_ENIGMA = 2*ACTION + 130*INFILTRATING + 2*INTERCEPTED_CABLEGRAM
|
SEARING_ENIGMA = 2*ACTION + 130*INFILTRATING + 2*INTERCEPTED_CABLEGRAM
|
||||||
|
|
||||||
|
# Segmented Ribcage
|
||||||
|
# No consistent source
|
||||||
|
SEGMENTED_RIBCAGE = cp_model.INT32_MAX/4
|
||||||
|
|
||||||
# Carved Ball of Stygian Ivory
|
# Carved Ball of Stygian Ivory
|
||||||
STYGIAN_IVORY = 250
|
STYGIAN_IVORY = 250
|
||||||
|
|
||||||
|
|
|
@ -124,6 +124,16 @@ class Skull(Enum):
|
||||||
menace = 1
|
menace = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Requires Torso Style 110
|
||||||
|
SEGMENTED_RIBCAGE = Action(
|
||||||
|
'Affix a Segmented Ribcage as the "skull"',
|
||||||
|
cost = Cost.ACTION.value + Cost.SEGMENTED_RIBCAGE.value,
|
||||||
|
value = 250,
|
||||||
|
skulls_needed = -1,
|
||||||
|
limbs_needed = 4,
|
||||||
|
segments = 1
|
||||||
|
)
|
||||||
|
|
||||||
STYGIAN_IVORY = Action(
|
STYGIAN_IVORY = Action(
|
||||||
"Use a Carved Ball of Stygian Ivory to cap off your (Skeleton Type)",
|
"Use a Carved Ball of Stygian Ivory to cap off your (Skeleton Type)",
|
||||||
cost = Cost.ACTION.value + Cost.STYGIAN_IVORY.value,
|
cost = Cost.ACTION.value + Cost.STYGIAN_IVORY.value,
|
||||||
|
|
|
@ -134,5 +134,16 @@ class Torso(Enum):
|
||||||
menace = 1
|
menace = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SEGMENTED_RIBCAGE = Action(
|
||||||
|
"Build on a Segmented Ribcage",
|
||||||
|
cost = Cost.ACTION.value + Cost.SEGMENTED_RIBCAGE.value,
|
||||||
|
torso_style = 110,
|
||||||
|
value = 250,
|
||||||
|
skulls_needed = 1,
|
||||||
|
limbs_needed = 2,
|
||||||
|
tails_needed = 1,
|
||||||
|
segments = 1,
|
||||||
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.value)
|
return str(self.value)
|
||||||
|
|
|
@ -47,6 +47,9 @@ class Action:
|
||||||
# Skeleton: Fins
|
# Skeleton: Fins
|
||||||
fins: int = 0
|
fins: int = 0
|
||||||
|
|
||||||
|
# Skeleton: Number of Segments
|
||||||
|
segments: int = 0
|
||||||
|
|
||||||
# Skeleton: Tentacles
|
# Skeleton: Tentacles
|
||||||
tentacles: int = 0
|
tentacles: int = 0
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ __all__ = ['Adjustment', 'Appendage', 'Buyer', 'Declaration', 'DiplomatFascinati
|
||||||
__author__ = "Jeremy Saklad"
|
__author__ = "Jeremy Saklad"
|
||||||
|
|
||||||
from functools import partialmethod
|
from functools import partialmethod
|
||||||
from itertools import chain
|
from itertools import chain, repeat
|
||||||
from os import cpu_count
|
from os import cpu_count
|
||||||
|
|
||||||
from ortools.sat.python import cp_model
|
from ortools.sat.python import cp_model
|
||||||
|
@ -167,6 +167,10 @@ def Solve(shadowy_level, bone_market_fluctuations = None, zoological_mania = Non
|
||||||
fins = model.NewIntVar('fins', lb = 0)
|
fins = model.NewIntVar('fins', lb = 0)
|
||||||
model.Add(fins == cp_model.LinearExpr.WeightedSum(actions.values(), [action.value.fins for action in actions.keys()]))
|
model.Add(fins == cp_model.LinearExpr.WeightedSum(actions.values(), [action.value.fins for action in actions.keys()]))
|
||||||
|
|
||||||
|
# Segments calculation
|
||||||
|
segments = model.NewIntVar('segments', lb = 0)
|
||||||
|
model.Add(segments == cp_model.LinearExpr.WeightedSum(actions.values(), [action.value.segments for action in actions.keys()]))
|
||||||
|
|
||||||
# Tentacles calculation
|
# Tentacles calculation
|
||||||
tentacles = model.NewIntVar('tentacles', lb = 0)
|
tentacles = model.NewIntVar('tentacles', lb = 0)
|
||||||
model.Add(tentacles == cp_model.LinearExpr.WeightedSum(actions.values(), [action.value.tentacles for action in actions.keys()]))
|
model.Add(tentacles == cp_model.LinearExpr.WeightedSum(actions.values(), [action.value.tentacles for action in actions.keys()]))
|
||||||
|
@ -326,10 +330,139 @@ def Solve(shadowy_level, bone_market_fluctuations = None, zoological_mania = Non
|
||||||
del add_joints, add_joints_amber_cost_multiple
|
del add_joints, add_joints_amber_cost_multiple
|
||||||
|
|
||||||
|
|
||||||
cost = model.NewIntVar('cost', lb = 0, ub = maximum_cost)
|
# Calculate cost of adding segments.
|
||||||
model.Add(cost == cp_model.LinearExpr.WeightedSum(actions.values(), [int(action.value.cost) for action in actions.keys()]) + add_joints_amber_cost + sale_cost)
|
# This is a partial sum formula.
|
||||||
|
add_segments_brass_cost = model.NewIntVar('add segments brass cost', lb = 0)
|
||||||
|
|
||||||
del sale_cost, add_joints_amber_cost
|
add_segments = actions[Appendage.SEGMENTED_RIBCAGE]
|
||||||
|
|
||||||
|
# Additional segments may be added once the torso and skulls are chosen, so the sum of their properties are the starting point.
|
||||||
|
base_segments = model.NewIntVar('base segments', lb = 0)
|
||||||
|
model.Add(base_segments == cp_model.LinearExpr.WeightedSum([value for (key, value) in actions.items() if isinstance(key, (Torso, Skull))], [action.value.segments for action in chain(Torso, Skull)]))
|
||||||
|
|
||||||
|
first_term, *_ = model.NewIntermediateIntVar(
|
||||||
|
partialmethod(BoneMarketModel.AddMultiplicationEquality,
|
||||||
|
variables=(
|
||||||
|
25,
|
||||||
|
*repeat(add_segments, 4),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'add segments brass cost multiple first term'
|
||||||
|
)
|
||||||
|
|
||||||
|
second_term, *_ = model.NewIntermediateIntVar(
|
||||||
|
partialmethod(BoneMarketModel.AddMultiplicationEquality,
|
||||||
|
variables=(
|
||||||
|
100,
|
||||||
|
*repeat(add_segments, 3),
|
||||||
|
base_segments,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'add segments brass cost multiple second term'
|
||||||
|
)
|
||||||
|
|
||||||
|
third_term, *_ = model.NewIntermediateIntVar(
|
||||||
|
partialmethod(BoneMarketModel.AddMultiplicationEquality,
|
||||||
|
variables=(
|
||||||
|
50,
|
||||||
|
*repeat(add_segments, 3),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'add segments brass cost multiple third term'
|
||||||
|
)
|
||||||
|
|
||||||
|
fourth_term, *_ = model.NewIntermediateIntVar(
|
||||||
|
partialmethod(BoneMarketModel.AddMultiplicationEquality,
|
||||||
|
variables=(
|
||||||
|
150,
|
||||||
|
*repeat(add_segments, 2),
|
||||||
|
*repeat(base_segments, 2),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'add segments brass cost multiple fourth term'
|
||||||
|
)
|
||||||
|
|
||||||
|
fifth_term, *_ = model.NewIntermediateIntVar(
|
||||||
|
partialmethod(BoneMarketModel.AddMultiplicationEquality,
|
||||||
|
variables=(
|
||||||
|
150,
|
||||||
|
*repeat(add_segments, 2),
|
||||||
|
base_segments,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'add segments brass cost multiple fifth term'
|
||||||
|
)
|
||||||
|
|
||||||
|
sixth_term, *_ = model.NewIntermediateIntVar(
|
||||||
|
partialmethod(BoneMarketModel.AddMultiplicationEquality,
|
||||||
|
variables=(
|
||||||
|
25,
|
||||||
|
*repeat(add_segments, 2),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'add segments brass cost multiple sixth term'
|
||||||
|
)
|
||||||
|
|
||||||
|
seventh_term, *_ = model.NewIntermediateIntVar(
|
||||||
|
partialmethod(BoneMarketModel.AddMultiplicationEquality,
|
||||||
|
variables=(
|
||||||
|
100,
|
||||||
|
add_segments,
|
||||||
|
*repeat(base_segments, 3),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'add segments brass cost multiple seventh term'
|
||||||
|
)
|
||||||
|
|
||||||
|
eighth_term, *_ = model.NewIntermediateIntVar(
|
||||||
|
partialmethod(BoneMarketModel.AddMultiplicationEquality,
|
||||||
|
variables=(
|
||||||
|
150,
|
||||||
|
add_segments,
|
||||||
|
*repeat(base_segments, 2),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'add segments brass cost multiple eighth term'
|
||||||
|
)
|
||||||
|
|
||||||
|
ninth_term, *_ = model.NewIntermediateIntVar(
|
||||||
|
partialmethod(BoneMarketModel.AddMultiplicationEquality,
|
||||||
|
variables=(
|
||||||
|
50,
|
||||||
|
add_segments,
|
||||||
|
base_segments,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'add segments brass cost multiple ninth term'
|
||||||
|
)
|
||||||
|
|
||||||
|
add_segments_brass_cost_multiple, *_ = model.NewIntermediateIntVar(
|
||||||
|
partialmethod(BoneMarketModel.AddDivisionEquality,
|
||||||
|
num=first_term + second_term + third_term + fourth_term + fifth_term + sixth_term + seventh_term + eighth_term + ninth_term,
|
||||||
|
denom=2
|
||||||
|
),
|
||||||
|
'add segments brass cost multiple'
|
||||||
|
)
|
||||||
|
|
||||||
|
del first_term, second_term, third_term, fourth_term, fifth_term, sixth_term, seventh_term, eighth_term, ninth_term
|
||||||
|
|
||||||
|
add_segments_brass_cost, *_ = model.NewIntermediateIntVar(
|
||||||
|
partialmethod(BoneMarketModel.AddMultiplicationEquality,
|
||||||
|
variables=(
|
||||||
|
add_segments_brass_cost_multiple,
|
||||||
|
Cost.NEVERCOLD_BRASS.value,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'add segments brass cost'
|
||||||
|
)
|
||||||
|
|
||||||
|
del add_segments, base_segments, add_segments_brass_cost_multiple
|
||||||
|
|
||||||
|
|
||||||
|
cost = model.NewIntVar('cost', lb = 0, ub = maximum_cost)
|
||||||
|
model.Add(cost == cp_model.LinearExpr.WeightedSum(actions.values(), [int(action.value.cost) for action in actions.keys()]) + add_joints_amber_cost + add_segments_brass_cost + sale_cost)
|
||||||
|
|
||||||
|
del sale_cost, add_joints_amber_cost, add_segments_brass_cost
|
||||||
|
|
||||||
|
|
||||||
# Type of skeleton
|
# Type of skeleton
|
||||||
|
@ -443,6 +576,20 @@ def Solve(shadowy_level, bone_market_fluctuations = None, zoological_mania = Non
|
||||||
.OnlyEnforceIf(actions[Declaration.CURATOR])
|
.OnlyEnforceIf(actions[Declaration.CURATOR])
|
||||||
|
|
||||||
|
|
||||||
|
# Skull requirements
|
||||||
|
|
||||||
|
model.Add(torso_style == 110) \
|
||||||
|
.OnlyEnforceIf(model.BoolExpression(actions[Skull.SEGMENTED_RIBCAGE] > 0))
|
||||||
|
|
||||||
|
|
||||||
|
# Appendage requirements
|
||||||
|
|
||||||
|
model.AddIf(model.BoolExpression(actions[Appendage.SEGMENTED_RIBCAGE] > 0),
|
||||||
|
torso_style == 110,
|
||||||
|
cp_model.LinearExpr.WeightedSum([value for (key, value) in actions.items() if isinstance(key, (Torso, Skull))], [action.value.tails_needed for action in chain(Torso, Skull)]) >= 1,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Declaration requirements
|
# Declaration requirements
|
||||||
|
|
||||||
model.AddIf(actions[Declaration.HUMANOID],
|
model.AddIf(actions[Declaration.HUMANOID],
|
||||||
|
|
Loading…
Reference in New Issue