2021-06-18 20:28:56 +00:00
""" Use constraint programming to devise the optimal skeleton at the Bone Market in Fallen London. """
2021-08-03 17:53:25 +00:00
__all__ = [ ' Buyer ' , ' Declaration ' , ' DiplomatFascination ' , ' Fluctuation ' , ' OccasionalBuyer ' , ' Solve ' ]
2021-06-18 20:28:56 +00:00
__author__ = " Jeremy Saklad "
2021-06-18 20:08:28 +00:00
from functools import reduce
from os import cpu_count
2021-06-08 22:28:15 +00:00
from ortools . sat . python import cp_model
2021-08-03 19:48:42 +00:00
from . data . adjustments import Adjustment
from . data . appendages import Appendage
from . data . buyers import Buyer
from . data . costs import Cost
from . data . declarations import Declaration
from . data . diplomat_fascinations import DiplomatFascination
from . data . embellishments import Embellishment
from . data . fluctuations import Fluctuation
from . data . occasional_buyers import OccasionalBuyer
from . data . skulls import Skull
from . data . torsos import Torso
2021-08-03 17:02:06 +00:00
2021-06-08 22:28:15 +00:00
# This multiplier is applied to the profit margin to avoid losing precision due to rounding.
PROFIT_MARGIN_MULTIPLIER = 10000000
# This is the highest number of attribute to calculate fractional exponents for.
MAXIMUM_ATTRIBUTE = 100
# This is a constant used to calculate difficulty checks. You almost certainly do not need to change this.
DIFFICULTY_SCALER = 0.6
def NewIntermediateBoolVar ( self , name , expression , domain ) :
2021-06-18 19:44:30 +00:00
""" Add a fully-reified implication using an intermediate Boolean variable. """
2021-06-08 22:28:15 +00:00
intermediate = self . NewBoolVar ( name )
self . AddLinearExpressionInDomain ( expression , domain ) . OnlyEnforceIf ( intermediate )
self . AddLinearExpressionInDomain ( expression , domain . Complement ( ) ) . OnlyEnforceIf ( intermediate . Not ( ) )
return intermediate
2021-07-06 16:27:13 +00:00
cp_model . CpModel . NewIntermediateBoolVar = NewIntermediateBoolVar
2021-06-08 22:28:15 +00:00
del NewIntermediateBoolVar
def AddApproximateExponentiationEquality ( self , target , var , exp , upto ) :
2021-06-18 19:44:30 +00:00
""" Add an approximate exponentiation equality using a lookup table.
Set ` upto ` to a value that is unlikely to come into play .
"""
2021-06-08 22:28:15 +00:00
return self . AddAllowedAssignments ( [ target , var ] , [ ( int ( base * * exp ) , base ) for base in range ( upto + 1 ) ] )
2021-07-06 16:27:13 +00:00
cp_model . CpModel . AddApproximateExponentiationEquality = AddApproximateExponentiationEquality
2021-06-08 22:28:15 +00:00
del AddApproximateExponentiationEquality
def AddGeneralMultiplicationEquality ( self , target , * variables ) :
2021-06-18 19:44:30 +00:00
""" Add a multiplication equality for any number of terms using intermediate variables. """
2021-06-08 22:28:15 +00:00
# This is used for producing unique names for intermediate variables.
term_index = 1
def function ( a , b ) :
nonlocal term_index
intermediate = self . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} term {} ' . format ( target . Name ( ) , term_index ) )
term_index + = 1
self . AddMultiplicationEquality ( intermediate , [ a , b ] )
return intermediate
2021-06-18 20:08:28 +00:00
product = reduce ( function , variables )
2021-06-08 22:28:15 +00:00
return self . Add ( target == product )
2021-07-06 16:27:13 +00:00
cp_model . CpModel . AddGeneralMultiplicationEquality = AddGeneralMultiplicationEquality
2021-06-08 22:28:15 +00:00
del AddGeneralMultiplicationEquality
2021-07-11 20:45:04 +00:00
def Solve ( shadowy_level , bone_market_fluctuations = None , zoological_mania = None , occasional_buyer = None , diplomat_fascination = None , desired_buyers = [ ] , maximum_cost = cp_model . INT32_MAX , maximum_exhaustion = cp_model . INT32_MAX , time_limit = float ( ' inf ' ) , workers = cpu_count ( ) , stdscr = None ) :
2021-06-08 22:28:15 +00:00
model = cp_model . CpModel ( )
actions = { }
2021-06-13 17:37:15 +00:00
# Torso
for torso in Torso :
actions [ torso ] = model . NewBoolVar ( torso . value . name )
# Skull
for skull in Skull :
actions [ skull ] = model . NewIntVar ( 0 , cp_model . INT32_MAX , skull . value . name )
# Appendage
for appendage in Appendage :
if appendage == Appendage . SKIP_TAILS :
actions [ appendage ] = model . NewBoolVar ( appendage . value . name )
2021-06-08 22:28:15 +00:00
else :
2021-06-13 17:37:15 +00:00
actions [ appendage ] = model . NewIntVar ( 0 , cp_model . INT32_MAX , appendage . value . name )
2021-06-15 22:27:59 +00:00
# Avoid adding joints at first
model . AddHint ( actions [ Appendage . ADD_JOINTS ] , 0 )
2021-06-08 22:28:15 +00:00
2021-06-13 17:37:15 +00:00
# Adjustment
for adjustment in Adjustment :
actions [ adjustment ] = model . NewIntVar ( 0 , cp_model . INT32_MAX , adjustment . value . name )
2021-06-08 22:28:15 +00:00
2021-06-13 17:37:15 +00:00
# Declaration
2021-06-08 22:28:15 +00:00
for declaration in Declaration :
2021-06-13 17:37:15 +00:00
actions [ declaration ] = model . NewBoolVar ( declaration . value . name )
2021-06-15 22:27:59 +00:00
# Try non-Chimera declarations first
model . AddHint ( actions [ Declaration . CHIMERA ] , 0 )
2021-06-13 17:37:15 +00:00
2021-06-13 19:27:53 +00:00
# Embellishment
for embellishment in Embellishment :
actions [ embellishment ] = model . NewIntVar ( 0 , cp_model . INT32_MAX , embellishment . value . name )
2021-06-16 20:30:48 +00:00
2021-06-13 22:37:39 +00:00
# Buyer
for buyer in Buyer :
actions [ buyer ] = model . NewBoolVar ( buyer . value . name )
2021-06-16 20:30:48 +00:00
# Mark unavailable buyers
model . AddAssumptions ( [
actions [ buyer ] . Not ( )
for unavailable_buyer in OccasionalBuyer if unavailable_buyer != occasional_buyer
2021-06-16 22:28:16 +00:00
for buyer in unavailable_buyer . value if buyer not in desired_buyers
2021-06-16 20:30:48 +00:00
] )
2021-06-25 23:37:41 +00:00
model . AddAssumptions ( [
actions [ outmoded_fascination . value ] . Not ( )
for outmoded_fascination in DiplomatFascination if outmoded_fascination != diplomat_fascination and outmoded_fascination . value not in desired_buyers
] )
2021-06-16 20:30:48 +00:00
2021-06-16 22:28:16 +00:00
# Restrict to desired buyers
if desired_buyers :
model . Add ( cp_model . LinearExpr . Sum ( [ actions [ desired_buyer ] for desired_buyer in desired_buyers ] ) == 1 )
2021-06-16 20:30:48 +00:00
2021-06-13 17:37:15 +00:00
# One torso
model . Add ( cp_model . LinearExpr . Sum ( [ value for ( key , value ) in actions . items ( ) if isinstance ( key , Torso ) ] ) == 1 )
# One declaration
model . Add ( cp_model . LinearExpr . Sum ( [ value for ( key , value ) in actions . items ( ) if isinstance ( key , Declaration ) ] ) == 1 )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
# One buyer
model . Add ( cp_model . LinearExpr . Sum ( [ value for ( key , value ) in actions . items ( ) if isinstance ( key , Buyer ) ] ) == 1 )
2021-06-08 22:28:15 +00:00
# Value calculation
original_value = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' original value ' )
2021-06-13 17:37:15 +00:00
model . Add ( original_value == cp_model . LinearExpr . ScalProd ( actions . values ( ) , [ action . value . value for action in actions . keys ( ) ] ) )
2021-06-08 22:28:15 +00:00
2021-07-11 20:45:04 +00:00
value = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' value ' )
2021-06-24 13:45:59 +00:00
2021-07-11 20:45:04 +00:00
if zoological_mania :
multiplier = 115 if zoological_mania in [ Declaration . FISH , Declaration . INSECT , Declaration . SPIDER ] else 110
2021-06-08 22:28:15 +00:00
2021-07-11 20:45:04 +00:00
multiplied_value = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' multiplied value ' )
model . Add ( multiplied_value == multiplier * original_value ) . OnlyEnforceIf ( actions [ zoological_mania ] )
model . Add ( multiplied_value == 100 * original_value ) . OnlyEnforceIf ( actions [ zoological_mania ] . Not ( ) )
model . AddDivisionEquality ( value , multiplied_value , 100 )
else :
model . Add ( value == original_value )
2021-06-08 22:28:15 +00:00
2021-07-11 20:45:04 +00:00
del original_value
2021-06-08 22:28:15 +00:00
# Torso Style calculation
2021-06-18 18:49:44 +00:00
torso_style = model . NewIntVarFromDomain ( cp_model . Domain . FromValues ( [ torso . value . torso_style for torso in Torso ] ) , ' torso style ' )
2021-06-13 17:37:15 +00:00
for torso , torso_variable in { key : value for ( key , value ) in actions . items ( ) if isinstance ( key , Torso ) } . items ( ) :
model . Add ( torso_style == torso . value . torso_style ) . OnlyEnforceIf ( torso_variable )
2021-06-08 22:28:15 +00:00
# Skulls calculation
skulls = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' skulls ' )
2021-06-13 17:37:15 +00:00
model . Add ( skulls == cp_model . LinearExpr . ScalProd ( actions . values ( ) , [ action . value . skulls for action in actions . keys ( ) ] ) )
2021-06-08 22:28:15 +00:00
# Arms calculation
arms = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' arms ' )
2021-06-13 17:37:15 +00:00
model . Add ( arms == cp_model . LinearExpr . ScalProd ( actions . values ( ) , [ action . value . arms for action in actions . keys ( ) ] ) )
2021-06-08 22:28:15 +00:00
# Legs calculation
legs = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' legs ' )
2021-06-13 17:37:15 +00:00
model . Add ( legs == cp_model . LinearExpr . ScalProd ( actions . values ( ) , [ action . value . legs for action in actions . keys ( ) ] ) )
2021-06-08 22:28:15 +00:00
# Tails calculation
tails = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' tails ' )
2021-06-13 17:37:15 +00:00
model . Add ( tails == cp_model . LinearExpr . ScalProd ( actions . values ( ) , [ action . value . tails for action in actions . keys ( ) ] ) )
2021-06-08 22:28:15 +00:00
# Wings calculation
wings = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' wings ' )
2021-06-13 17:37:15 +00:00
model . Add ( wings == cp_model . LinearExpr . ScalProd ( actions . values ( ) , [ action . value . wings for action in actions . keys ( ) ] ) )
2021-06-08 22:28:15 +00:00
# Fins calculation
fins = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' fins ' )
2021-06-13 17:37:15 +00:00
model . Add ( fins == cp_model . LinearExpr . ScalProd ( actions . values ( ) , [ action . value . fins for action in actions . keys ( ) ] ) )
2021-06-08 22:28:15 +00:00
# Tentacles calculation
tentacles = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' tentacles ' )
2021-06-13 17:37:15 +00:00
model . Add ( tentacles == cp_model . LinearExpr . ScalProd ( actions . values ( ) , [ action . value . tentacles for action in actions . keys ( ) ] ) )
2021-06-08 22:28:15 +00:00
# Amalgamy calculation
amalgamy = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' amalgamy ' )
2021-06-13 17:37:15 +00:00
model . Add ( amalgamy == cp_model . LinearExpr . ScalProd ( actions . values ( ) , [ action . value . amalgamy for action in actions . keys ( ) ] ) )
2021-06-08 22:28:15 +00:00
# Antiquity calculation
antiquity = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' antiquity ' )
2021-06-13 17:37:15 +00:00
model . Add ( antiquity == cp_model . LinearExpr . ScalProd ( actions . values ( ) , [ action . value . antiquity for action in actions . keys ( ) ] ) )
2021-06-08 22:28:15 +00:00
# Menace calculation
menace = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' menace ' )
2021-06-13 17:37:15 +00:00
model . Add ( menace == cp_model . LinearExpr . ScalProd ( actions . values ( ) , [ action . value . menace for action in actions . keys ( ) ] ) )
2021-06-08 22:28:15 +00:00
# Implausibility calculation
implausibility = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' implausibility ' )
2021-06-13 17:37:15 +00:00
model . Add ( implausibility == cp_model . LinearExpr . ScalProd ( actions . values ( ) , [ action . value . implausibility for action in actions . keys ( ) ] ) )
2021-06-08 22:28:15 +00:00
2021-06-13 18:23:23 +00:00
2021-06-08 22:28:15 +00:00
# Counter-church calculation
# Calculate amount of Counter-church from Holy Relics of the Thigh of Saint Fiacre
2021-06-13 17:37:15 +00:00
holy_relic = actions [ Appendage . FIACRE_THIGH ]
2021-06-08 22:28:15 +00:00
torso_style_divided_by_ten = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' torso style divided by ten ' )
model . AddDivisionEquality ( torso_style_divided_by_ten , torso_style , 10 )
holy_relic_counter_church = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' holy relic counter-church ' )
model . AddMultiplicationEquality ( holy_relic_counter_church , [ holy_relic , torso_style_divided_by_ten ] )
counter_church = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' counter-church ' )
2021-06-13 17:37:15 +00:00
model . Add ( counter_church == cp_model . LinearExpr . ScalProd ( actions . values ( ) , [ action . value . counter_church for action in actions . keys ( ) ] ) + holy_relic_counter_church )
2021-06-08 22:28:15 +00:00
del holy_relic , torso_style_divided_by_ten , holy_relic_counter_church
2021-06-13 18:23:23 +00:00
2021-06-08 22:28:15 +00:00
# Exhaustion calculation
2021-06-14 00:40:11 +00:00
exhaustion = model . NewIntVar ( 0 , maximum_exhaustion , ' exhaustion ' )
2021-06-08 22:28:15 +00:00
2021-06-13 18:23:23 +00:00
# Exhaustion added by certain buyers
2021-06-14 00:40:11 +00:00
added_exhaustion = model . NewIntVar ( 0 , maximum_exhaustion , ' added exhaustion ' )
2021-06-13 18:23:23 +00:00
model . Add ( exhaustion == cp_model . LinearExpr . ScalProd ( actions . values ( ) , [ action . value . exhaustion for action in actions . keys ( ) ] ) + added_exhaustion )
2021-06-08 22:28:15 +00:00
# Profit intermediate variables
primary_revenue = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' primary revenue ' )
secondary_revenue = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' secondary revenue ' )
total_revenue = model . NewIntVar ( 0 , cp_model . INT32_MAX * 2 , ' total revenue ' )
model . Add ( total_revenue == cp_model . LinearExpr . Sum ( [ primary_revenue , secondary_revenue ] ) )
# Cost
# Calculate value of actions needed to sell the skeleton.
2021-06-13 19:27:53 +00:00
difficulty_level = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' difficulty level ' )
2021-06-08 22:28:15 +00:00
non_zero_difficulty_level = model . NewIntVar ( 1 , cp_model . INT32_MAX , ' non-zero difficulty level ' )
model . AddMaxEquality ( non_zero_difficulty_level , [ difficulty_level , 1 ] )
sale_actions_times_action_value = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' sale actions times action value ' )
2021-06-19 12:32:19 +00:00
model . AddDivisionEquality ( sale_actions_times_action_value , model . NewConstant ( round ( DIFFICULTY_SCALER * shadowy_level * Cost . ACTION . value ) ) , non_zero_difficulty_level )
2021-06-08 22:28:15 +00:00
abstract_sale_cost = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' abstract sale cost ' )
2021-06-13 17:43:52 +00:00
model . AddDivisionEquality ( abstract_sale_cost , Cost . ACTION . value * * 2 , sale_actions_times_action_value )
2021-06-08 22:28:15 +00:00
sale_cost = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' sale cost ' )
2021-06-13 17:43:52 +00:00
model . AddMaxEquality ( sale_cost , [ abstract_sale_cost , Cost . ACTION . value ] )
2021-06-08 22:28:15 +00:00
del non_zero_difficulty_level , sale_actions_times_action_value , abstract_sale_cost
# Calculate cost of adding joints
# This is a partial sum formula.
add_joints_amber_cost = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' add joints amber cost ' )
2021-06-13 17:37:15 +00:00
add_joints = actions [ Appendage . ADD_JOINTS ]
2021-06-08 22:28:15 +00:00
base_joints = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' base joints ' )
2021-06-17 16:26:24 +00:00
model . Add ( base_joints == cp_model . LinearExpr . ScalProd ( [ value for ( key , value ) in actions . items ( ) if isinstance ( key , Torso ) ] , [ torso . value . limbs_needed + torso . value . arms + torso . value . legs + torso . value . wings + torso . value . fins + torso . value . tentacles for torso in Torso ] ) )
2021-06-08 22:28:15 +00:00
add_joints_amber_cost_multiple = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' add joints amber cost multiple ' )
add_joints_amber_cost_multiple_first_term = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' add joints amber cost multiple first term ' )
2021-06-11 23:04:21 +00:00
model . AddGeneralMultiplicationEquality ( add_joints_amber_cost_multiple_first_term , 25 , base_joints , base_joints , add_joints )
2021-06-08 22:28:15 +00:00
add_joints_amber_cost_multiple_second_term = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' add joints amber cost multiple second term ' )
2021-06-11 23:04:21 +00:00
model . AddGeneralMultiplicationEquality ( add_joints_amber_cost_multiple_second_term , 100 , base_joints , add_joints , add_joints )
2021-06-08 22:28:15 +00:00
add_joints_amber_cost_multiple_third_term = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' add joints amber cost multiple third term ' )
2021-06-11 23:04:21 +00:00
model . AddGeneralMultiplicationEquality ( add_joints_amber_cost_multiple_third_term , 100 , base_joints , add_joints )
2021-06-08 22:28:15 +00:00
add_joints_amber_cost_multiple_fourth_term = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' add joints amber cost multiple fourth term ' )
add_joints_amber_cost_multiple_fourth_term_numerator = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' add joints amber cost multiple fourth term numerator ' )
add_joints_amber_cost_multiple_fourth_term_numerator_first_term = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' add joints amber cost multiple fourth term numerator first term ' )
2021-06-11 23:04:21 +00:00
model . AddGeneralMultiplicationEquality ( add_joints_amber_cost_multiple_fourth_term_numerator_first_term , 400 , add_joints , add_joints , add_joints )
model . Add ( add_joints_amber_cost_multiple_fourth_term_numerator == add_joints_amber_cost_multiple_fourth_term_numerator_first_term + 200 * add_joints )
2021-06-08 22:28:15 +00:00
model . AddDivisionEquality ( add_joints_amber_cost_multiple_fourth_term , add_joints_amber_cost_multiple_fourth_term_numerator , 3 )
del add_joints_amber_cost_multiple_fourth_term_numerator , add_joints_amber_cost_multiple_fourth_term_numerator_first_term
add_joints_amber_cost_multiple_fifth_term = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' add joints amber cost multiple fifth term ' )
2021-06-11 23:04:21 +00:00
model . AddGeneralMultiplicationEquality ( add_joints_amber_cost_multiple_fifth_term , 200 , add_joints , add_joints )
2021-06-08 22:28:15 +00:00
model . Add ( add_joints_amber_cost_multiple == add_joints_amber_cost_multiple_first_term + add_joints_amber_cost_multiple_second_term - add_joints_amber_cost_multiple_third_term + add_joints_amber_cost_multiple_fourth_term - add_joints_amber_cost_multiple_fifth_term )
del add_joints_amber_cost_multiple_first_term , add_joints_amber_cost_multiple_second_term , add_joints_amber_cost_multiple_third_term , add_joints_amber_cost_multiple_fourth_term , add_joints_amber_cost_multiple_fifth_term
2021-06-13 17:43:52 +00:00
model . AddGeneralMultiplicationEquality ( add_joints_amber_cost , add_joints , add_joints_amber_cost_multiple , Cost . WARM_AMBER . value )
2021-06-08 22:28:15 +00:00
del add_joints , add_joints_amber_cost_multiple
2021-06-14 00:40:11 +00:00
cost = model . NewIntVar ( 0 , maximum_cost , ' cost ' )
2021-06-13 17:37:15 +00:00
model . Add ( cost == cp_model . LinearExpr . ScalProd ( actions . values ( ) , [ int ( action . value . cost ) for action in actions . keys ( ) ] ) + add_joints_amber_cost + sale_cost )
2021-06-08 22:28:15 +00:00
del sale_cost , add_joints_amber_cost
# Type of skeleton
skeleton_in_progress = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' skeleton in progress ' )
# Chimera
model . Add ( skeleton_in_progress == 100 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . CHIMERA ] )
2021-06-08 22:28:15 +00:00
# Humanoid
model . Add ( skeleton_in_progress == 110 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . HUMANOID ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' humanoid antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ cp_model . INT_MIN , 0 ] ) ) )
# Ancient Humanoid (UNCERTAIN)
model . Add ( skeleton_in_progress == 111 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . HUMANOID ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' ancient humanoid antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ 1 , 5 ] ) ) )
# Neanderthal
model . Add ( skeleton_in_progress == 112 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . HUMANOID ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' neanderthal antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ 6 , cp_model . INT_MAX ] ) ) )
# Ape (UNCERTAIN)
model . Add ( skeleton_in_progress == 120 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . APE ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' ape antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ cp_model . INT_MIN , 1 ] ) ) )
# Primordial Ape (UNCERTAIN)
model . Add ( skeleton_in_progress == 121 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . APE ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' primordial ape antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ 2 , cp_model . INT_MAX ] ) ) )
# Monkey
model . Add ( skeleton_in_progress == 125 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . MONKEY ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' monkey antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ cp_model . INT_MIN , 0 ] ) ) )
# Catarrhine Monkey (UNCERTAIN)
model . Add ( skeleton_in_progress == 126 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . MONKEY ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' catarrhine monkey 126 antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ 1 , 8 ] ) ) )
# Catarrhine Monkey
model . Add ( skeleton_in_progress == 128 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . MONKEY ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' catarrhine monkey 128 antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ 9 , cp_model . INT_MAX ] ) ) )
# Crocodile
model . Add ( skeleton_in_progress == 160 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . REPTILE ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' crocodile antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ cp_model . INT_MIN , 1 ] ) ) )
# Dinosaur
model . Add ( skeleton_in_progress == 161 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . REPTILE ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' dinosaur antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ 2 , 4 ] ) ) )
# Mesosaur (UNCERTAIN)
model . Add ( skeleton_in_progress == 162 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . REPTILE ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' mesosaur antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ 5 , cp_model . INT_MAX ] ) ) )
# Toad
model . Add ( skeleton_in_progress == 170 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . AMPHIBIAN ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' toad antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ cp_model . INT_MIN , 1 ] ) ) )
# Primordial Amphibian
model . Add ( skeleton_in_progress == 171 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . AMPHIBIAN ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' primordial amphibian antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ 2 , 4 ] ) ) )
# Temnospondyl
model . Add ( skeleton_in_progress == 172 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . AMPHIBIAN ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' temnospondyl antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ 5 , cp_model . INT_MAX ] ) ) )
# Owl
model . Add ( skeleton_in_progress == 180 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . BIRD ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' owl antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ cp_model . INT_MIN , 1 ] ) ) )
# Archaeopteryx
model . Add ( skeleton_in_progress == 181 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . BIRD ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' archaeopteryx antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ 2 , 4 ] ) ) )
# Ornithomimosaur (UNCERTAIN)
model . Add ( skeleton_in_progress == 182 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . BIRD ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' ornithomimosaur antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ 5 , cp_model . INT_MAX ] ) ) )
# Lamprey
model . Add ( skeleton_in_progress == 190 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . FISH ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' lamprey antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ cp_model . INT_MIN , 0 ] ) ) )
# Coelacanth (UNCERTAIN)
model . Add ( skeleton_in_progress == 191 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . FISH ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' coelacanth antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ 1 , cp_model . INT_MAX ] ) ) )
# Spider (UNCERTAIN)
model . Add ( skeleton_in_progress == 200 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . SPIDER ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' spider antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ cp_model . INT_MIN , 1 ] ) ) )
# Primordial Orb-Weaver (UNCERTAIN)
model . Add ( skeleton_in_progress == 201 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . SPIDER ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' primordial orb-weaver antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ 2 , 7 ] ) ) )
# Trigonotarbid
model . Add ( skeleton_in_progress == 203 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . SPIDER ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' trigonotarbid antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ 8 , cp_model . INT_MAX ] ) ) )
# Beetle (UNCERTAIN)
model . Add ( skeleton_in_progress == 210 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . INSECT ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' beetle antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ cp_model . INT_MIN , 1 ] ) ) )
# Primordial Beetle (UNCERTAIN)
model . Add ( skeleton_in_progress == 211 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . INSECT ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' primordial beetle antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ 2 , 6 ] ) ) )
# Rhyniognatha
model . Add ( skeleton_in_progress == 212 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . INSECT ] ) \
2021-06-08 22:28:15 +00:00
. OnlyEnforceIf ( model . NewIntermediateBoolVar ( ' rhyniognatha antiquity ' , antiquity , cp_model . Domain . FromFlatIntervals ( [ 7 , cp_model . INT_MAX ] ) ) )
# Curator
model . Add ( skeleton_in_progress == 300 ) \
2021-06-13 17:37:15 +00:00
. OnlyEnforceIf ( actions [ Declaration . CURATOR ] )
2021-06-08 22:28:15 +00:00
# Humanoid requirements
2021-06-13 17:37:15 +00:00
model . Add ( skulls == 1 ) . OnlyEnforceIf ( actions [ Declaration . HUMANOID ] )
model . Add ( legs == 2 ) . OnlyEnforceIf ( actions [ Declaration . HUMANOID ] )
model . Add ( arms == 2 ) . OnlyEnforceIf ( actions [ Declaration . HUMANOID ] )
2021-07-07 20:12:03 +00:00
model . AddLinearExpressionInDomain ( torso_style , cp_model . Domain . FromFlatIntervals ( [ 10 , 20 ] ) ) . OnlyEnforceIf ( actions [ Declaration . HUMANOID ] )
2021-06-08 22:28:15 +00:00
for prohibited_quality in [ tails , fins , wings ] :
2021-06-13 17:37:15 +00:00
model . Add ( prohibited_quality == 0 ) . OnlyEnforceIf ( actions [ Declaration . HUMANOID ] )
2021-06-08 22:28:15 +00:00
# Ape requirements
2021-06-13 17:37:15 +00:00
model . Add ( skulls == 1 ) . OnlyEnforceIf ( actions [ Declaration . APE ] )
model . Add ( arms == 4 ) . OnlyEnforceIf ( actions [ Declaration . APE ] )
2021-07-07 20:12:03 +00:00
model . AddLinearExpressionInDomain ( torso_style , cp_model . Domain . FromFlatIntervals ( [ 10 , 20 ] ) ) . OnlyEnforceIf ( actions [ Declaration . APE ] )
2021-06-08 22:28:15 +00:00
for prohibited_quality in [ legs , tails , fins , wings ] :
2021-06-13 17:37:15 +00:00
model . Add ( prohibited_quality == 0 ) . OnlyEnforceIf ( actions [ Declaration . APE ] )
2021-06-08 22:28:15 +00:00
# Monkey requirements
2021-06-13 17:37:15 +00:00
model . Add ( skulls == 1 ) . OnlyEnforceIf ( actions [ Declaration . MONKEY ] )
model . Add ( arms == 4 ) . OnlyEnforceIf ( actions [ Declaration . MONKEY ] )
model . Add ( tails == 1 ) . OnlyEnforceIf ( actions [ Declaration . MONKEY ] )
2021-07-07 20:12:03 +00:00
model . AddLinearExpressionInDomain ( torso_style , cp_model . Domain . FromFlatIntervals ( [ 10 , 20 ] ) ) . OnlyEnforceIf ( actions [ Declaration . MONKEY ] )
2021-06-08 22:28:15 +00:00
for prohibited_quality in [ legs , fins , wings ] :
2021-06-13 17:37:15 +00:00
model . Add ( prohibited_quality == 0 ) . OnlyEnforceIf ( actions [ Declaration . MONKEY ] )
2021-06-08 22:28:15 +00:00
# Bird requirements
2021-06-13 17:37:15 +00:00
model . Add ( legs == 2 ) . OnlyEnforceIf ( actions [ Declaration . BIRD ] )
model . Add ( wings == 2 ) . OnlyEnforceIf ( actions [ Declaration . BIRD ] )
model . Add ( torso_style > = 20 ) . OnlyEnforceIf ( actions [ Declaration . BIRD ] )
2021-06-08 22:28:15 +00:00
for prohibited_quality in [ arms , fins ] :
2021-06-13 17:37:15 +00:00
model . Add ( prohibited_quality == 0 ) . OnlyEnforceIf ( actions [ Declaration . BIRD ] )
model . Add ( tails < 2 ) . OnlyEnforceIf ( actions [ Declaration . BIRD ] )
2021-06-08 22:28:15 +00:00
# Curator requirements
2021-06-13 17:37:15 +00:00
model . Add ( skulls == 1 ) . OnlyEnforceIf ( actions [ Declaration . CURATOR ] )
model . Add ( arms == 2 ) . OnlyEnforceIf ( actions [ Declaration . CURATOR ] )
model . Add ( legs == 2 ) . OnlyEnforceIf ( actions [ Declaration . CURATOR ] )
model . Add ( wings == 2 ) . OnlyEnforceIf ( actions [ Declaration . CURATOR ] )
2021-06-08 22:28:15 +00:00
for prohibited_quality in [ fins , tails ] :
2021-06-13 17:37:15 +00:00
model . Add ( prohibited_quality == 0 ) . OnlyEnforceIf ( actions [ Declaration . CURATOR ] )
2021-06-08 22:28:15 +00:00
# Reptile requirements
2021-06-13 17:37:15 +00:00
model . Add ( torso_style > = 20 ) . OnlyEnforceIf ( actions [ Declaration . REPTILE ] )
model . Add ( tails == 1 ) . OnlyEnforceIf ( actions [ Declaration . REPTILE ] )
model . Add ( skulls == 1 ) . OnlyEnforceIf ( actions [ Declaration . REPTILE ] )
2021-06-08 22:28:15 +00:00
for prohibited_quality in [ fins , wings , arms ] :
2021-06-13 17:37:15 +00:00
model . Add ( prohibited_quality == 0 ) . OnlyEnforceIf ( actions [ Declaration . REPTILE ] )
model . Add ( legs < 5 ) . OnlyEnforceIf ( actions [ Declaration . REPTILE ] )
2021-06-08 22:28:15 +00:00
# Amphibian requirements
2021-06-13 17:37:15 +00:00
model . Add ( torso_style > = 20 ) . OnlyEnforceIf ( actions [ Declaration . AMPHIBIAN ] )
model . Add ( legs == 4 ) . OnlyEnforceIf ( actions [ Declaration . AMPHIBIAN ] )
model . Add ( skulls == 1 ) . OnlyEnforceIf ( actions [ Declaration . AMPHIBIAN ] )
2021-06-08 22:28:15 +00:00
for prohibited_quality in [ tails , fins , wings , arms ] :
2021-06-13 17:37:15 +00:00
model . Add ( prohibited_quality == 0 ) . OnlyEnforceIf ( actions [ Declaration . AMPHIBIAN ] )
2021-06-08 22:28:15 +00:00
# Fish requirements
2021-06-13 17:37:15 +00:00
model . Add ( skulls == 1 ) . OnlyEnforceIf ( actions [ Declaration . FISH ] )
model . Add ( fins > = 2 ) . OnlyEnforceIf ( actions [ Declaration . FISH ] )
model . Add ( tails < = 1 ) . OnlyEnforceIf ( actions [ Declaration . FISH ] )
model . Add ( torso_style > = 20 ) . OnlyEnforceIf ( actions [ Declaration . FISH ] )
2021-06-08 22:28:15 +00:00
for prohibited_quality in [ arms , legs , wings ] :
2021-06-13 17:37:15 +00:00
model . Add ( prohibited_quality == 0 ) . OnlyEnforceIf ( actions [ Declaration . FISH ] )
2021-06-08 22:28:15 +00:00
# Insect requirements
2021-06-13 17:37:15 +00:00
model . Add ( skulls == 1 ) . OnlyEnforceIf ( actions [ Declaration . INSECT ] )
model . Add ( legs == 6 ) . OnlyEnforceIf ( actions [ Declaration . INSECT ] )
model . Add ( torso_style > = 20 ) . OnlyEnforceIf ( actions [ Declaration . INSECT ] )
2021-06-08 22:28:15 +00:00
for prohibited_quality in [ arms , fins , tails ] :
2021-06-13 17:37:15 +00:00
model . Add ( prohibited_quality == 0 ) . OnlyEnforceIf ( actions [ Declaration . INSECT ] )
model . Add ( wings < 5 ) . OnlyEnforceIf ( actions [ Declaration . INSECT ] )
2021-06-08 22:28:15 +00:00
# Spider requirements
2021-06-13 17:37:15 +00:00
model . Add ( legs == 8 ) . OnlyEnforceIf ( actions [ Declaration . SPIDER ] )
model . Add ( tails < = 1 ) . OnlyEnforceIf ( actions [ Declaration . SPIDER ] )
model . Add ( torso_style > = 20 ) . OnlyEnforceIf ( actions [ Declaration . SPIDER ] )
2021-06-08 22:28:15 +00:00
for prohibited_quality in [ skulls , arms , wings , fins ] :
2021-06-13 17:37:15 +00:00
model . Add ( prohibited_quality == 0 ) . OnlyEnforceIf ( actions [ Declaration . SPIDER ] )
# Skeleton must have no unfilled skulls
model . Add ( cp_model . LinearExpr . ScalProd ( actions . values ( ) , [ action . value . skulls_needed for action in actions . keys ( ) ] ) == 0 )
# Skeleton must have no unfilled limbs
model . Add ( cp_model . LinearExpr . ScalProd ( actions . values ( ) , [ action . value . limbs_needed for action in actions . keys ( ) ] ) == 0 )
2021-06-08 22:28:15 +00:00
2021-06-13 17:37:15 +00:00
# Skeleton must have no unfilled tails, unless they were skipped
model . Add ( cp_model . LinearExpr . ScalProd ( actions . values ( ) , [ action . value . tails_needed for action in actions . keys ( ) ] ) == 0 ) . OnlyEnforceIf ( actions [ Appendage . SKIP_TAILS ] . Not ( ) )
2021-07-07 20:12:03 +00:00
model . Add ( cp_model . LinearExpr . ScalProd ( actions . values ( ) , [ action . value . tails_needed for action in actions . keys ( ) ] ) > 0 ) . OnlyEnforceIf ( actions [ Appendage . SKIP_TAILS ] )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
# A Palaeontologist with Hoarding Propensities
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . A_PALAEONTOLOGIST_WITH_HOARDING_PROPENSITIES ] )
model . Add ( primary_revenue == value + 5 ) . OnlyEnforceIf ( actions [ Buyer . A_PALAEONTOLOGIST_WITH_HOARDING_PROPENSITIES ] )
model . Add ( secondary_revenue == 500 ) . OnlyEnforceIf ( actions [ Buyer . A_PALAEONTOLOGIST_WITH_HOARDING_PROPENSITIES ] )
model . Add ( difficulty_level == 40 * implausibility ) . OnlyEnforceIf ( actions [ Buyer . A_PALAEONTOLOGIST_WITH_HOARDING_PROPENSITIES ] )
model . Add ( added_exhaustion == 0 ) . OnlyEnforceIf ( actions [ Buyer . A_PALAEONTOLOGIST_WITH_HOARDING_PROPENSITIES ] )
# A Naive Collector
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . A_NAIVE_COLLECTOR ] )
value_remainder = model . NewIntVar ( 0 , 249 , ' {} : {} ' . format ( Buyer . A_NAIVE_COLLECTOR . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 250 )
model . Add ( primary_revenue == value - value_remainder ) . OnlyEnforceIf ( actions [ Buyer . A_NAIVE_COLLECTOR ] )
model . Add ( secondary_revenue == 0 ) . OnlyEnforceIf ( actions [ Buyer . A_NAIVE_COLLECTOR ] )
model . Add ( difficulty_level == 25 * implausibility ) . OnlyEnforceIf ( actions [ Buyer . A_NAIVE_COLLECTOR ] )
model . Add ( added_exhaustion == 0 ) . OnlyEnforceIf ( actions [ Buyer . A_NAIVE_COLLECTOR ] )
del value_remainder
# A Familiar Bohemian Sculptress
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . A_FAMILIAR_BOHEMIAN_SCULPTRESS ] )
model . Add ( antiquity < = 0 ) . OnlyEnforceIf ( actions [ Buyer . A_FAMILIAR_BOHEMIAN_SCULPTRESS ] )
value_remainder = model . NewIntVar ( 0 , 249 , ' {} : {} ' . format ( Buyer . A_FAMILIAR_BOHEMIAN_SCULPTRESS . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 250 )
model . Add ( primary_revenue == value - value_remainder + 1000 ) . OnlyEnforceIf ( actions [ Buyer . A_FAMILIAR_BOHEMIAN_SCULPTRESS ] )
model . Add ( secondary_revenue == 250 * counter_church ) . OnlyEnforceIf ( actions [ Buyer . A_FAMILIAR_BOHEMIAN_SCULPTRESS ] )
model . Add ( difficulty_level == 50 * implausibility ) . OnlyEnforceIf ( actions [ Buyer . A_FAMILIAR_BOHEMIAN_SCULPTRESS ] )
model . Add ( added_exhaustion == 0 ) . OnlyEnforceIf ( actions [ Buyer . A_FAMILIAR_BOHEMIAN_SCULPTRESS ] )
del value_remainder
# A Pedagogically Inclined Grandmother
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . A_PEDAGOGICALLY_INCLINED_GRANDMOTHER ] )
model . Add ( menace < = 0 ) . OnlyEnforceIf ( actions [ Buyer . A_PEDAGOGICALLY_INCLINED_GRANDMOTHER ] )
value_remainder = model . NewIntVar ( 0 , 49 , ' {} : {} ' . format ( Buyer . A_PEDAGOGICALLY_INCLINED_GRANDMOTHER . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 50 )
model . Add ( primary_revenue == value - value_remainder + 1000 ) . OnlyEnforceIf ( actions [ Buyer . A_PEDAGOGICALLY_INCLINED_GRANDMOTHER ] )
model . Add ( secondary_revenue == 0 ) . OnlyEnforceIf ( actions [ Buyer . A_PEDAGOGICALLY_INCLINED_GRANDMOTHER ] )
model . Add ( difficulty_level == 50 * implausibility ) . OnlyEnforceIf ( actions [ Buyer . A_PEDAGOGICALLY_INCLINED_GRANDMOTHER ] )
model . Add ( added_exhaustion == 0 ) . OnlyEnforceIf ( actions [ Buyer . A_PEDAGOGICALLY_INCLINED_GRANDMOTHER ] )
del value_remainder
# A Theologian of the Old School
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . A_THEOLOGIAN_OF_THE_OLD_SCHOOL ] )
model . Add ( amalgamy < = 0 ) . OnlyEnforceIf ( actions [ Buyer . A_THEOLOGIAN_OF_THE_OLD_SCHOOL ] )
value_remainder = model . NewIntVar ( 0 , 249 , ' {} : {} ' . format ( Buyer . A_THEOLOGIAN_OF_THE_OLD_SCHOOL . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 250 )
model . Add ( primary_revenue == value - value_remainder + 1000 ) . OnlyEnforceIf ( actions [ Buyer . A_THEOLOGIAN_OF_THE_OLD_SCHOOL ] )
model . Add ( secondary_revenue == 0 ) . OnlyEnforceIf ( actions [ Buyer . A_THEOLOGIAN_OF_THE_OLD_SCHOOL ] )
model . Add ( difficulty_level == 50 * implausibility ) . OnlyEnforceIf ( actions [ Buyer . A_THEOLOGIAN_OF_THE_OLD_SCHOOL ] )
model . Add ( added_exhaustion == 0 ) . OnlyEnforceIf ( actions [ Buyer . A_THEOLOGIAN_OF_THE_OLD_SCHOOL ] )
del value_remainder
# An Enthusiast of the Ancient World
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTHUSIAST_OF_THE_ANCIENT_WORLD ] )
model . Add ( antiquity > 0 ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTHUSIAST_OF_THE_ANCIENT_WORLD ] )
value_remainder = model . NewIntVar ( 0 , 49 , ' {} : {} ' . format ( Buyer . AN_ENTHUSIAST_OF_THE_ANCIENT_WORLD . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 50 )
model . Add ( primary_revenue == value - value_remainder ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTHUSIAST_OF_THE_ANCIENT_WORLD ] )
2021-06-14 00:40:11 +00:00
model . Add ( secondary_revenue == 250 * antiquity + ( 250 if bone_market_fluctuations == Fluctuation . ANTIQUITY else 0 ) ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTHUSIAST_OF_THE_ANCIENT_WORLD ] )
2021-06-13 22:37:39 +00:00
model . Add ( difficulty_level == 45 * implausibility ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTHUSIAST_OF_THE_ANCIENT_WORLD ] )
model . Add ( added_exhaustion == 0 ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTHUSIAST_OF_THE_ANCIENT_WORLD ] )
del value_remainder
# Mrs Plenty
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . MRS_PLENTY ] )
model . Add ( menace > 0 ) . OnlyEnforceIf ( actions [ Buyer . MRS_PLENTY ] )
value_remainder = model . NewIntVar ( 0 , 49 , ' {} : {} ' . format ( Buyer . MRS_PLENTY . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 50 )
model . Add ( primary_revenue == value - value_remainder ) . OnlyEnforceIf ( actions [ Buyer . MRS_PLENTY ] )
model . Add ( secondary_revenue == 250 * menace ) . OnlyEnforceIf ( actions [ Buyer . MRS_PLENTY ] )
model . Add ( difficulty_level == 45 * implausibility ) . OnlyEnforceIf ( actions [ Buyer . MRS_PLENTY ] )
model . Add ( added_exhaustion == 0 ) . OnlyEnforceIf ( actions [ Buyer . MRS_PLENTY ] )
del value_remainder
# A Tentacled Servant
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . A_TENTACLED_SERVANT ] )
model . Add ( amalgamy > 0 ) . OnlyEnforceIf ( actions [ Buyer . A_TENTACLED_SERVANT ] )
value_remainder = model . NewIntVar ( 0 , 49 , ' {} : {} ' . format ( Buyer . A_TENTACLED_SERVANT . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 50 )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
model . Add ( primary_revenue == value - value_remainder + 250 ) . OnlyEnforceIf ( actions [ Buyer . A_TENTACLED_SERVANT ] )
2021-06-14 00:40:11 +00:00
model . Add ( secondary_revenue == 250 * amalgamy + ( 250 if bone_market_fluctuations == Fluctuation . AMALGAMY else 0 ) ) . OnlyEnforceIf ( actions [ Buyer . A_TENTACLED_SERVANT ] )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
model . Add ( difficulty_level == 45 * implausibility ) . OnlyEnforceIf ( actions [ Buyer . A_TENTACLED_SERVANT ] )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
model . Add ( added_exhaustion == 0 ) . OnlyEnforceIf ( actions [ Buyer . A_TENTACLED_SERVANT ] )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
del value_remainder
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
# An Investment-Minded Ambassador
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . AN_INVESTMENT_MINDED_AMBASSADOR ] )
model . Add ( antiquity > 0 ) . OnlyEnforceIf ( actions [ Buyer . AN_INVESTMENT_MINDED_AMBASSADOR ] )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
antiquity_squared = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . AN_INVESTMENT_MINDED_AMBASSADOR . name , ' antiquity squared ' ) )
model . AddMultiplicationEquality ( antiquity_squared , [ antiquity , antiquity ] )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
tailfeathers = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . AN_INVESTMENT_MINDED_AMBASSADOR . name , ' tailfeathers ' ) )
2021-06-14 00:40:11 +00:00
if bone_market_fluctuations == Fluctuation . ANTIQUITY :
2021-06-22 10:45:33 +00:00
model . AddApproximateExponentiationEquality ( tailfeathers , antiquity , 2.1 , MAXIMUM_ATTRIBUTE )
2021-06-13 22:37:39 +00:00
else :
model . Add ( tailfeathers == antiquity_squared ) . OnlyEnforceIf ( actions [ Buyer . AN_INVESTMENT_MINDED_AMBASSADOR ] )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
value_remainder = model . NewIntVar ( 0 , 49 , ' {} : {} ' . format ( Buyer . AN_INVESTMENT_MINDED_AMBASSADOR . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 50 )
extra_value = model . NewIntermediateBoolVar ( ' {} : {} ' . format ( Buyer . AN_INVESTMENT_MINDED_AMBASSADOR . name , ' extra value ' ) , value_remainder , cp_model . Domain . FromFlatIntervals ( [ 0 , cp_model . INT_MAX ] ) )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
model . Add ( primary_revenue == value + 50 * extra_value + 250 ) . OnlyEnforceIf ( actions [ Buyer . AN_INVESTMENT_MINDED_AMBASSADOR ] )
model . Add ( secondary_revenue == 250 * tailfeathers ) . OnlyEnforceIf ( actions [ Buyer . AN_INVESTMENT_MINDED_AMBASSADOR ] )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
model . Add ( difficulty_level == 75 * implausibility ) . OnlyEnforceIf ( actions [ Buyer . AN_INVESTMENT_MINDED_AMBASSADOR ] )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
# The indirection is necessary for applying an enforcement literal
derived_exhaustion = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . AN_INVESTMENT_MINDED_AMBASSADOR . name , ' derived exhaustion ' ) )
model . AddDivisionEquality ( derived_exhaustion , antiquity_squared , 20 )
model . Add ( added_exhaustion == derived_exhaustion ) . OnlyEnforceIf ( actions [ Buyer . AN_INVESTMENT_MINDED_AMBASSADOR ] )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
del antiquity_squared , tailfeathers , value_remainder , extra_value , derived_exhaustion
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
# A Teller of Terrors
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . A_TELLER_OF_TERRORS ] )
model . Add ( menace > 0 ) . OnlyEnforceIf ( actions [ Buyer . A_TELLER_OF_TERRORS ] )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
menace_squared = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_TELLER_OF_TERRORS . name , ' menace squared ' ) )
model . AddMultiplicationEquality ( menace_squared , [ menace , menace ] )
2021-06-08 22:28:15 +00:00
2021-07-06 18:19:29 +00:00
feathers = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_TELLER_OF_TERRORS . name , ' feathers ' ) )
if bone_market_fluctuations == Fluctuation . MENACE :
model . AddApproximateExponentiationEquality ( feathers , menace , 2.1 , MAXIMUM_ATTRIBUTE )
else :
model . Add ( feathers == menace_squared ) . OnlyEnforceIf ( actions [ Buyer . A_TELLER_OF_TERRORS ] )
2021-06-13 22:37:39 +00:00
value_remainder = model . NewIntVar ( 0 , 9 , ' {} : {} ' . format ( Buyer . A_TELLER_OF_TERRORS . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 10 )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
model . Add ( primary_revenue == value - value_remainder + 50 ) . OnlyEnforceIf ( actions [ Buyer . A_TELLER_OF_TERRORS ] )
2021-07-06 18:19:29 +00:00
model . Add ( secondary_revenue == 50 * feathers ) . OnlyEnforceIf ( actions [ Buyer . A_TELLER_OF_TERRORS ] )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
model . Add ( difficulty_level == 75 * implausibility ) . OnlyEnforceIf ( actions [ Buyer . A_TELLER_OF_TERRORS ] )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
# The indirection is necessary for applying an enforcement literal
derived_exhaustion = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_TELLER_OF_TERRORS . name , ' derived exhaustion ' ) )
model . AddDivisionEquality ( derived_exhaustion , menace_squared , 100 )
model . Add ( added_exhaustion == derived_exhaustion ) . OnlyEnforceIf ( actions [ Buyer . A_TELLER_OF_TERRORS ] )
2021-06-08 22:28:15 +00:00
2021-07-06 18:19:29 +00:00
del menace_squared , feathers , value_remainder , derived_exhaustion
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
# A Tentacled Entrepreneur
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . A_TENTACLED_ENTREPRENEUR ] )
model . Add ( amalgamy > 0 ) . OnlyEnforceIf ( actions [ Buyer . A_TENTACLED_ENTREPRENEUR ] )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
amalgamy_squared = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_TENTACLED_ENTREPRENEUR . name , ' amalgamy squared ' ) )
model . AddMultiplicationEquality ( amalgamy_squared , [ amalgamy , amalgamy ] )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
final_breaths = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_TENTACLED_ENTREPRENEUR . name , ' final breaths ' ) )
2021-06-14 00:40:11 +00:00
if bone_market_fluctuations == Fluctuation . AMALGAMY :
2021-06-22 10:45:33 +00:00
model . AddApproximateExponentiationEquality ( final_breaths , amalgamy , 2.1 , MAXIMUM_ATTRIBUTE )
2021-06-13 22:37:39 +00:00
else :
model . Add ( final_breaths == amalgamy_squared ) . OnlyEnforceIf ( actions [ Buyer . A_TENTACLED_ENTREPRENEUR ] )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
value_remainder = model . NewIntVar ( 0 , 49 , ' {} : {} ' . format ( Buyer . A_TENTACLED_ENTREPRENEUR . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 50 )
2021-06-13 18:46:45 +00:00
2021-06-13 22:37:39 +00:00
model . Add ( primary_revenue == value - value_remainder + 250 ) . OnlyEnforceIf ( actions [ Buyer . A_TENTACLED_ENTREPRENEUR ] )
model . Add ( secondary_revenue == 50 * final_breaths ) . OnlyEnforceIf ( actions [ Buyer . A_TENTACLED_ENTREPRENEUR ] )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
model . Add ( difficulty_level == 75 * implausibility ) . OnlyEnforceIf ( actions [ Buyer . A_TENTACLED_ENTREPRENEUR ] )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
# The indirection is necessary for applying an enforcement literal
derived_exhaustion = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_TENTACLED_ENTREPRENEUR . name , ' derived exhaustion ' ) )
model . AddDivisionEquality ( derived_exhaustion , amalgamy_squared , 100 )
model . Add ( added_exhaustion == derived_exhaustion ) . OnlyEnforceIf ( actions [ Buyer . A_TENTACLED_ENTREPRENEUR ] )
2021-06-08 22:28:15 +00:00
2021-06-13 22:37:39 +00:00
del amalgamy_squared , final_breaths , value_remainder , derived_exhaustion
# An Author of Gothic Tales
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . AN_AUTHOR_OF_GOTHIC_TALES ] )
model . Add ( antiquity > 0 ) . OnlyEnforceIf ( actions [ Buyer . AN_AUTHOR_OF_GOTHIC_TALES ] )
model . Add ( menace > 0 ) . OnlyEnforceIf ( actions [ Buyer . AN_AUTHOR_OF_GOTHIC_TALES ] )
antiquity_times_menace = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . AN_AUTHOR_OF_GOTHIC_TALES . name , ' antiquity times menace ' ) )
model . AddMultiplicationEquality ( antiquity_times_menace , [ antiquity , menace ] )
2021-06-22 14:04:41 +00:00
antiquity_fluctuation_bonus = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . AN_AUTHOR_OF_GOTHIC_TALES . name , ' antiquity fluctuation bonus ' ) )
2021-07-07 19:17:55 +00:00
model . AddDivisionEquality ( antiquity_fluctuation_bonus , antiquity , 2 )
2021-06-22 14:04:41 +00:00
2021-07-06 18:19:29 +00:00
menace_fluctuation_bonus = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . AN_AUTHOR_OF_GOTHIC_TALES . name , ' menace fluctuation bonus ' ) )
2021-07-07 19:17:55 +00:00
model . AddDivisionEquality ( menace_fluctuation_bonus , menace , 2 )
2021-07-06 18:19:29 +00:00
2021-06-13 22:37:39 +00:00
value_remainder = model . NewIntVar ( 0 , 49 , ' {} : {} ' . format ( Buyer . AN_AUTHOR_OF_GOTHIC_TALES . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 50 )
model . Add ( primary_revenue == value - value_remainder + 250 ) . OnlyEnforceIf ( actions [ Buyer . AN_AUTHOR_OF_GOTHIC_TALES ] )
2021-07-06 18:19:29 +00:00
model . Add ( secondary_revenue == 250 * antiquity_times_menace + 250 * ( antiquity_fluctuation_bonus if bone_market_fluctuations == Fluctuation . ANTIQUITY else menace_fluctuation_bonus if bone_market_fluctuations == Fluctuation . MENACE else 0 ) ) . OnlyEnforceIf ( actions [ Buyer . AN_AUTHOR_OF_GOTHIC_TALES ] )
2021-06-13 22:37:39 +00:00
model . Add ( difficulty_level == 75 * implausibility ) . OnlyEnforceIf ( actions [ Buyer . AN_AUTHOR_OF_GOTHIC_TALES ] )
# The indirection is necessary for applying an enforcement literal
derived_exhaustion = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . AN_AUTHOR_OF_GOTHIC_TALES . name , ' derived exhaustion ' ) )
model . AddDivisionEquality ( derived_exhaustion , antiquity_times_menace , 20 )
model . Add ( added_exhaustion == derived_exhaustion ) . OnlyEnforceIf ( actions [ Buyer . AN_AUTHOR_OF_GOTHIC_TALES ] )
2021-07-07 19:17:55 +00:00
del antiquity_times_menace , antiquity_fluctuation_bonus , menace_fluctuation_bonus , value_remainder , derived_exhaustion
2021-06-13 22:37:39 +00:00
# A Zailor with Particular Interests
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . A_ZAILOR_WITH_PARTICULAR_INTERESTS ] )
model . Add ( antiquity > 0 ) . OnlyEnforceIf ( actions [ Buyer . A_ZAILOR_WITH_PARTICULAR_INTERESTS ] )
model . Add ( amalgamy > 0 ) . OnlyEnforceIf ( actions [ Buyer . A_ZAILOR_WITH_PARTICULAR_INTERESTS ] )
amalgamy_times_antiquity = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_ZAILOR_WITH_PARTICULAR_INTERESTS . name , ' amalgamy times antiquity ' ) )
model . AddMultiplicationEquality ( amalgamy_times_antiquity , [ amalgamy , antiquity ] )
2021-06-22 14:04:41 +00:00
amalgamy_fluctuation_bonus = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_ZAILOR_WITH_PARTICULAR_INTERESTS . name , ' amalgamy fluctuation bonus ' ) )
2021-07-07 19:17:55 +00:00
model . AddDivisionEquality ( amalgamy_fluctuation_bonus , amalgamy , 2 )
2021-06-22 14:04:41 +00:00
antiquity_fluctuation_bonus = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_ZAILOR_WITH_PARTICULAR_INTERESTS . name , ' antiquity fluctuation bonus ' ) )
2021-07-07 19:17:55 +00:00
model . AddDivisionEquality ( antiquity_fluctuation_bonus , antiquity , 2 )
2021-06-22 14:04:41 +00:00
2021-06-13 22:37:39 +00:00
value_remainder = model . NewIntVar ( 0 , 9 , ' {} : {} ' . format ( Buyer . A_ZAILOR_WITH_PARTICULAR_INTERESTS . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 10 )
model . Add ( primary_revenue == value - value_remainder + 250 ) . OnlyEnforceIf ( actions [ Buyer . A_ZAILOR_WITH_PARTICULAR_INTERESTS ] )
2021-06-22 14:04:41 +00:00
model . Add ( secondary_revenue == 250 * amalgamy_times_antiquity + 250 * ( amalgamy_fluctuation_bonus if bone_market_fluctuations == Fluctuation . AMALGAMY else antiquity_fluctuation_bonus if bone_market_fluctuations == Fluctuation . ANTIQUITY else 0 ) ) . OnlyEnforceIf ( actions [ Buyer . A_ZAILOR_WITH_PARTICULAR_INTERESTS ] )
2021-06-13 22:37:39 +00:00
model . Add ( difficulty_level == 75 * implausibility ) . OnlyEnforceIf ( actions [ Buyer . A_ZAILOR_WITH_PARTICULAR_INTERESTS ] )
# The indirection is necessary for applying an enforcement literal
derived_exhaustion = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_ZAILOR_WITH_PARTICULAR_INTERESTS . name , ' derived exhaustion ' ) )
model . AddDivisionEquality ( derived_exhaustion , amalgamy_times_antiquity , 20 )
model . Add ( added_exhaustion == derived_exhaustion ) . OnlyEnforceIf ( actions [ Buyer . A_ZAILOR_WITH_PARTICULAR_INTERESTS ] )
2021-07-07 19:17:55 +00:00
del amalgamy_times_antiquity , amalgamy_fluctuation_bonus , antiquity_fluctuation_bonus , value_remainder , derived_exhaustion
2021-06-13 22:37:39 +00:00
# A Rubbery Collector
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . A_RUBBERY_COLLECTOR ] )
model . Add ( amalgamy > 0 ) . OnlyEnforceIf ( actions [ Buyer . A_RUBBERY_COLLECTOR ] )
model . Add ( menace > 0 ) . OnlyEnforceIf ( actions [ Buyer . A_RUBBERY_COLLECTOR ] )
amalgamy_times_menace = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_RUBBERY_COLLECTOR . name , ' amalgamy times menace ' ) )
model . AddMultiplicationEquality ( amalgamy_times_menace , [ amalgamy , menace ] )
2021-06-22 14:04:41 +00:00
amalgamy_fluctuation_bonus = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_RUBBERY_COLLECTOR . name , ' amalgamy fluctuation bonus ' ) )
2021-07-07 19:17:55 +00:00
model . AddDivisionEquality ( amalgamy_fluctuation_bonus , amalgamy , 2 )
2021-06-22 14:04:41 +00:00
2021-07-06 18:19:29 +00:00
menace_fluctuation_bonus = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_RUBBERY_COLLECTOR . name , ' menace fluctuation bonus ' ) )
2021-07-07 19:17:55 +00:00
model . AddDivisionEquality ( menace_fluctuation_bonus , menace , 2 )
2021-07-06 18:19:29 +00:00
2021-06-13 22:37:39 +00:00
value_remainder = model . NewIntVar ( 0 , 49 , ' {} : {} ' . format ( Buyer . A_RUBBERY_COLLECTOR . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 50 )
model . Add ( primary_revenue == value - value_remainder + 250 ) . OnlyEnforceIf ( actions [ Buyer . A_RUBBERY_COLLECTOR ] )
2021-07-06 18:19:29 +00:00
model . Add ( secondary_revenue == 250 * amalgamy_times_menace + 250 * ( amalgamy_fluctuation_bonus if bone_market_fluctuations == Fluctuation . AMALGAMY else menace_fluctuation_bonus if bone_market_fluctuations == Fluctuation . MENACE else 0 ) ) . OnlyEnforceIf ( actions [ Buyer . A_RUBBERY_COLLECTOR ] )
2021-06-13 22:37:39 +00:00
model . Add ( difficulty_level == 75 * implausibility ) . OnlyEnforceIf ( actions [ Buyer . A_RUBBERY_COLLECTOR ] )
# The indirection is necessary for applying an enforcement literal
derived_exhaustion = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_RUBBERY_COLLECTOR . name , ' derived exhaustion ' ) )
model . AddDivisionEquality ( derived_exhaustion , amalgamy_times_menace , 20 )
model . Add ( added_exhaustion == derived_exhaustion ) . OnlyEnforceIf ( actions [ Buyer . A_RUBBERY_COLLECTOR ] )
2021-07-07 19:17:55 +00:00
del amalgamy_times_menace , amalgamy_fluctuation_bonus , menace_fluctuation_bonus , value_remainder , derived_exhaustion
2021-06-13 22:37:39 +00:00
# A Constable
model . AddLinearExpressionInDomain ( skeleton_in_progress , cp_model . Domain . FromFlatIntervals ( [ 110 , 119 ] ) ) . OnlyEnforceIf ( actions [ Buyer . A_CONSTABLE ] )
value_remainder = model . NewIntVar ( 0 , 49 , ' {} : {} ' . format ( Buyer . A_CONSTABLE . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 50 )
model . Add ( primary_revenue == value - value_remainder + 1000 ) . OnlyEnforceIf ( actions [ Buyer . A_CONSTABLE ] )
model . Add ( secondary_revenue == 0 ) . OnlyEnforceIf ( actions [ Buyer . A_CONSTABLE ] )
model . Add ( difficulty_level == 50 * implausibility ) . OnlyEnforceIf ( actions [ Buyer . A_CONSTABLE ] )
model . Add ( added_exhaustion == 0 ) . OnlyEnforceIf ( actions [ Buyer . A_CONSTABLE ] )
del value_remainder
# An Enthusiast in Skulls
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTHUSIAST_IN_SKULLS ] )
model . Add ( skulls > = 2 ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTHUSIAST_IN_SKULLS ] )
extra_skulls = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . AN_ENTHUSIAST_IN_SKULLS . name , ' extra skulls ' ) )
model . Add ( extra_skulls == skulls - 1 ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTHUSIAST_IN_SKULLS ] )
vital_intelligence = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . AN_ENTHUSIAST_IN_SKULLS . name , ' vital intelligence ' ) )
model . AddApproximateExponentiationEquality ( vital_intelligence , extra_skulls , 1.8 , MAXIMUM_ATTRIBUTE )
model . Add ( primary_revenue == value ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTHUSIAST_IN_SKULLS ] )
model . Add ( secondary_revenue == 1250 * vital_intelligence ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTHUSIAST_IN_SKULLS ] )
model . Add ( difficulty_level == 60 * implausibility ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTHUSIAST_IN_SKULLS ] )
# The indirection is necessary for applying an enforcement literal
derived_exhaustion = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . AN_ENTHUSIAST_IN_SKULLS . name , ' derived exhaustion ' ) )
model . AddDivisionEquality ( derived_exhaustion , vital_intelligence , 4 )
model . Add ( added_exhaustion == derived_exhaustion ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTHUSIAST_IN_SKULLS ] )
del extra_skulls , vital_intelligence , derived_exhaustion
# A Dreary Midnighter
model . AddLinearExpressionInDomain ( skeleton_in_progress , cp_model . Domain . FromFlatIntervals ( [ 110 , 299 ] ) ) . OnlyEnforceIf ( actions [ Buyer . A_DREARY_MIDNIGHTER ] )
model . Add ( amalgamy < = 0 ) . OnlyEnforceIf ( actions [ Buyer . A_DREARY_MIDNIGHTER ] )
model . Add ( counter_church < = 0 ) . OnlyEnforceIf ( actions [ Buyer . A_DREARY_MIDNIGHTER ] )
value_remainder = model . NewIntVar ( 0 , 2 , ' {} : {} ' . format ( Buyer . A_DREARY_MIDNIGHTER . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 3 )
model . Add ( primary_revenue == value - value_remainder + 300 ) . OnlyEnforceIf ( actions [ Buyer . A_DREARY_MIDNIGHTER ] )
model . Add ( secondary_revenue == 250 ) . OnlyEnforceIf ( actions [ Buyer . A_DREARY_MIDNIGHTER ] )
model . Add ( difficulty_level == 100 * implausibility ) . OnlyEnforceIf ( actions [ Buyer . A_DREARY_MIDNIGHTER ] )
model . Add ( added_exhaustion == 0 ) . OnlyEnforceIf ( actions [ Buyer . A_DREARY_MIDNIGHTER ] )
del value_remainder
2021-06-15 11:56:05 +00:00
# A Colourful Phantasist - Bazaarine
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_BAZAARINE ] )
model . Add ( implausibility > = 2 ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_BAZAARINE ] )
model . Add ( amalgamy > = 4 ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_BAZAARINE ] )
amalgamy_times_implausibility = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_COLOURFUL_PHANTASIST_BAZAARINE . name , ' amalgamy times implausibility ' ) )
model . AddMultiplicationEquality ( amalgamy_times_implausibility , [ amalgamy , implausibility ] )
2021-06-16 20:53:10 +00:00
bazaarine_poetry = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_COLOURFUL_PHANTASIST_BAZAARINE . name , ' bazaarine poetry ' ) )
model . Add ( bazaarine_poetry == amalgamy_times_implausibility + 1 )
2021-06-15 11:56:05 +00:00
value_remainder = model . NewIntVar ( 0 , 49 , ' {} : {} ' . format ( Buyer . A_COLOURFUL_PHANTASIST_BAZAARINE . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 50 )
model . Add ( primary_revenue == value - value_remainder + 100 ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_BAZAARINE ] )
2021-06-16 20:53:10 +00:00
model . Add ( secondary_revenue == 250 * bazaarine_poetry ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_BAZAARINE ] )
2021-06-15 11:56:05 +00:00
model . Add ( difficulty_level == 0 ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_BAZAARINE ] )
# The indirection is necessary for applying an enforcement literal
2021-06-15 22:48:41 +00:00
derived_exhaustion = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_COLOURFUL_PHANTASIST_BAZAARINE . name , ' derived exhaustion ' ) )
2021-06-16 20:53:10 +00:00
model . AddDivisionEquality ( derived_exhaustion , bazaarine_poetry , 20 )
2021-06-15 11:56:05 +00:00
model . Add ( added_exhaustion == derived_exhaustion ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_BAZAARINE ] )
2021-06-16 20:53:10 +00:00
del amalgamy_times_implausibility , bazaarine_poetry , value_remainder , derived_exhaustion
2021-06-15 11:56:05 +00:00
2021-06-15 12:02:49 +00:00
# A Colourful Phantasist - Nocturnal
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_NOCTURNAL ] )
model . Add ( implausibility > = 2 ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_NOCTURNAL ] )
model . Add ( menace > = 4 ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_NOCTURNAL ] )
menace_times_implausibility = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_COLOURFUL_PHANTASIST_NOCTURNAL . name , ' menace times implausibility ' ) )
model . AddMultiplicationEquality ( menace_times_implausibility , [ menace , implausibility ] )
2021-06-16 20:53:10 +00:00
stygian_ivory = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_COLOURFUL_PHANTASIST_NOCTURNAL . name , ' stygian ivory ' ) )
model . Add ( stygian_ivory == menace_times_implausibility + 1 )
2021-06-15 12:02:49 +00:00
value_remainder = model . NewIntVar ( 0 , 49 , ' {} : {} ' . format ( Buyer . A_COLOURFUL_PHANTASIST_NOCTURNAL . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 50 )
model . Add ( primary_revenue == value - value_remainder + 100 ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_NOCTURNAL ] )
2021-06-16 20:53:10 +00:00
model . Add ( secondary_revenue == 250 * stygian_ivory ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_NOCTURNAL ] )
2021-06-15 12:02:49 +00:00
model . Add ( difficulty_level == 0 ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_NOCTURNAL ] )
# The indirection is necessary for applying an enforcement literal
2021-06-15 22:48:41 +00:00
derived_exhaustion = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_COLOURFUL_PHANTASIST_NOCTURNAL . name , ' derived exhaustion ' ) )
2021-06-16 20:53:10 +00:00
model . AddDivisionEquality ( derived_exhaustion , stygian_ivory , 20 )
2021-06-15 12:02:49 +00:00
model . Add ( added_exhaustion == derived_exhaustion ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_NOCTURNAL ] )
2021-06-16 20:53:10 +00:00
del menace_times_implausibility , stygian_ivory , value_remainder , derived_exhaustion
2021-06-15 12:02:49 +00:00
2021-06-15 12:10:20 +00:00
# A Colourful Phantasist - Celestial
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_CELESTIAL ] )
model . Add ( implausibility > = 2 ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_CELESTIAL ] )
model . Add ( antiquity > = 4 ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_CELESTIAL ] )
antiquity_times_implausibility = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_COLOURFUL_PHANTASIST_CELESTIAL . name , ' antiquity times implausibility ' ) )
model . AddMultiplicationEquality ( antiquity_times_implausibility , [ antiquity , implausibility ] )
2021-06-16 20:53:10 +00:00
knob_of_scintillack = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_COLOURFUL_PHANTASIST_CELESTIAL . name , ' knob of scintillack ' ) )
model . Add ( knob_of_scintillack == antiquity_times_implausibility + 1 )
2021-06-15 12:10:20 +00:00
value_remainder = model . NewIntVar ( 0 , 49 , ' {} : {} ' . format ( Buyer . A_COLOURFUL_PHANTASIST_CELESTIAL . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 50 )
model . Add ( primary_revenue == value - value_remainder + 100 ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_CELESTIAL ] )
2021-06-16 20:53:10 +00:00
model . Add ( secondary_revenue == 250 * knob_of_scintillack ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_CELESTIAL ] )
2021-06-15 12:10:20 +00:00
model . Add ( difficulty_level == 0 ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_CELESTIAL ] )
# The indirection is necessary for applying an enforcement literal
2021-06-15 22:48:41 +00:00
derived_exhaustion = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . A_COLOURFUL_PHANTASIST_CELESTIAL . name , ' derived exhaustion ' ) )
2021-06-16 20:53:10 +00:00
model . AddDivisionEquality ( derived_exhaustion , knob_of_scintillack , 20 )
2021-06-15 12:10:20 +00:00
model . Add ( added_exhaustion == derived_exhaustion ) . OnlyEnforceIf ( actions [ Buyer . A_COLOURFUL_PHANTASIST_CELESTIAL ] )
2021-06-16 20:53:10 +00:00
del antiquity_times_implausibility , knob_of_scintillack , value_remainder , derived_exhaustion
2021-06-15 12:10:20 +00:00
2021-06-22 13:25:12 +00:00
# An Ingenuous Malacologist
model . Add ( tentacles > = 4 ) . OnlyEnforceIf ( actions [ Buyer . AN_INGENUOUS_MALACOLOGIST ] )
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . AN_INGENUOUS_MALACOLOGIST ] )
exponentiated_tentacles = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . AN_INGENUOUS_MALACOLOGIST . name , ' exponentiated tentacles ' ) )
model . AddApproximateExponentiationEquality ( exponentiated_tentacles , tentacles , 2.2 , MAXIMUM_ATTRIBUTE )
collated_research = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . AN_INGENUOUS_MALACOLOGIST . name , ' collated research ' ) )
model . AddDivisionEquality ( collated_research , exponentiated_tentacles , 5 )
value_remainder = model . NewIntVar ( 0 , 249 , ' {} : {} ' . format ( Buyer . AN_INGENUOUS_MALACOLOGIST . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 250 )
model . Add ( primary_revenue == value - value_remainder + 250 ) . OnlyEnforceIf ( actions [ Buyer . AN_INGENUOUS_MALACOLOGIST ] )
model . Add ( secondary_revenue == 250 * collated_research ) . OnlyEnforceIf ( actions [ Buyer . AN_INGENUOUS_MALACOLOGIST ] )
model . Add ( difficulty_level == 60 * implausibility ) . OnlyEnforceIf ( actions [ Buyer . AN_INGENUOUS_MALACOLOGIST ] )
# The indirection is necessary for applying an enforcement literal
derived_exhaustion = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . AN_INGENUOUS_MALACOLOGIST . name , ' derived exhaustion ' ) )
model . AddDivisionEquality ( derived_exhaustion , exponentiated_tentacles , 100 )
model . Add ( added_exhaustion == derived_exhaustion ) . OnlyEnforceIf ( actions [ Buyer . AN_INGENUOUS_MALACOLOGIST ] )
del exponentiated_tentacles , collated_research , value_remainder , derived_exhaustion
2021-07-06 19:18:07 +00:00
# An Enterprising Boot Salesman
model . Add ( menace < = 0 ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTERPRISING_BOOT_SALESMAN ] )
model . Add ( amalgamy < = 0 ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTERPRISING_BOOT_SALESMAN ] )
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTERPRISING_BOOT_SALESMAN ] )
model . Add ( legs > = 4 ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTERPRISING_BOOT_SALESMAN ] )
diamonds = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . AN_ENTERPRISING_BOOT_SALESMAN . name , ' diamonds ' ) )
model . AddApproximateExponentiationEquality ( diamonds , legs , 2.2 , MAXIMUM_ATTRIBUTE )
value_remainder = model . NewIntVar ( 0 , 49 , ' {} : {} ' . format ( Buyer . AN_ENTERPRISING_BOOT_SALESMAN . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 50 )
model . Add ( primary_revenue == value - value_remainder ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTERPRISING_BOOT_SALESMAN ] )
model . Add ( secondary_revenue == 50 * diamonds ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTERPRISING_BOOT_SALESMAN ] )
model . Add ( difficulty_level == 0 ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTERPRISING_BOOT_SALESMAN ] )
# The indirection is necessary for applying an enforcement literal
derived_exhaustion = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . AN_ENTERPRISING_BOOT_SALESMAN . name , ' derived exhaustion ' ) )
model . AddDivisionEquality ( derived_exhaustion , diamonds , 100 )
model . Add ( added_exhaustion == derived_exhaustion ) . OnlyEnforceIf ( actions [ Buyer . AN_ENTERPRISING_BOOT_SALESMAN ] )
del diamonds , value_remainder , derived_exhaustion
2021-06-13 22:37:39 +00:00
# The Dumbwaiter of Balmoral
model . AddLinearExpressionInDomain ( skeleton_in_progress , cp_model . Domain . FromFlatIntervals ( [ 180 , 189 ] ) ) . OnlyEnforceIf ( actions [ Buyer . THE_DUMBWAITER_OF_BALMORAL ] )
model . Add ( value > = 250 ) . OnlyEnforceIf ( actions [ Buyer . THE_DUMBWAITER_OF_BALMORAL ] )
value_remainder = model . NewIntVar ( 0 , 249 , ' {} : {} ' . format ( Buyer . THE_DUMBWAITER_OF_BALMORAL . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 250 )
model . Add ( primary_revenue == value - value_remainder ) . OnlyEnforceIf ( actions [ Buyer . THE_DUMBWAITER_OF_BALMORAL ] )
model . Add ( secondary_revenue == 0 ) . OnlyEnforceIf ( actions [ Buyer . THE_DUMBWAITER_OF_BALMORAL ] )
model . Add ( difficulty_level == 200 ) . OnlyEnforceIf ( actions [ Buyer . THE_DUMBWAITER_OF_BALMORAL ] )
model . Add ( added_exhaustion == 0 ) . OnlyEnforceIf ( actions [ Buyer . THE_DUMBWAITER_OF_BALMORAL ] )
del value_remainder
2021-06-08 22:28:15 +00:00
2021-06-14 03:00:34 +00:00
# The Carpenter's Granddaughter
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . THE_CARPENTERS_GRANDDAUGHTER ] )
model . Add ( value > = 30000 ) . OnlyEnforceIf ( actions [ Buyer . THE_CARPENTERS_GRANDDAUGHTER ] )
model . Add ( primary_revenue == 31250 ) . OnlyEnforceIf ( actions [ Buyer . THE_CARPENTERS_GRANDDAUGHTER ] )
model . Add ( secondary_revenue == 0 ) . OnlyEnforceIf ( actions [ Buyer . THE_CARPENTERS_GRANDDAUGHTER ] )
model . Add ( difficulty_level == 100 * implausibility ) . OnlyEnforceIf ( actions [ Buyer . THE_CARPENTERS_GRANDDAUGHTER ] )
model . Add ( added_exhaustion == 0 ) . OnlyEnforceIf ( actions [ Buyer . THE_CARPENTERS_GRANDDAUGHTER ] )
2021-07-06 16:25:15 +00:00
# The Trifling Diplomat - Antiquity
model . Add ( skeleton_in_progress > = 100 ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_ANTIQUITY ] )
model . Add ( antiquity > = 5 ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_ANTIQUITY ] )
2021-06-25 23:37:41 +00:00
2021-07-06 16:25:15 +00:00
antiquity_squared = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_ANTIQUITY . name , ' antiquity squared ' ) )
2021-06-25 23:37:41 +00:00
model . AddMultiplicationEquality ( antiquity_squared , [ antiquity , antiquity ] )
2021-07-06 16:25:15 +00:00
value_remainder = model . NewIntVar ( 0 , 49 , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_ANTIQUITY . name , ' value remainder ' ) )
2021-06-25 23:37:41 +00:00
model . AddModuloEquality ( value_remainder , value , 50 )
2021-07-06 16:25:15 +00:00
model . Add ( primary_revenue == value - value_remainder + 50 ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_ANTIQUITY ] )
model . Add ( secondary_revenue == 50 * antiquity_squared ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_ANTIQUITY ] )
2021-06-25 23:37:41 +00:00
2021-07-06 16:25:15 +00:00
model . Add ( difficulty_level == 0 ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_ANTIQUITY ] )
2021-06-25 23:37:41 +00:00
# The indirection is necessary for applying an enforcement literal
2021-07-06 16:25:15 +00:00
derived_exhaustion = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_ANTIQUITY . name , ' derived exhaustion ' ) )
2021-06-25 23:37:41 +00:00
model . AddDivisionEquality ( derived_exhaustion , antiquity_squared , 100 )
2021-07-06 16:25:15 +00:00
model . Add ( added_exhaustion == derived_exhaustion ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_ANTIQUITY ] )
2021-06-25 23:37:41 +00:00
del antiquity_squared , value_remainder , derived_exhaustion
2021-07-06 17:33:03 +00:00
# The Trifling Diplomat - Bird
model . AddLinearExpressionInDomain ( skeleton_in_progress , cp_model . Domain . FromFlatIntervals ( [ 180 , 189 ] ) ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_BIRD ] )
non_negative_amalgamy = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_BIRD . name , ' non-negative amalgamy ' ) )
model . AddMaxEquality ( non_negative_amalgamy , [ amalgamy , 0 ] )
non_negative_menace = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_BIRD . name , ' non-negative menace ' ) )
model . AddMaxEquality ( non_negative_menace , [ menace , 0 ] )
non_negative_antiquity = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_BIRD . name , ' non-negative antiquity ' ) )
model . AddMaxEquality ( non_negative_antiquity , [ antiquity , 0 ] )
compromising_documents = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_BIRD . name , ' compromising documents ' ) )
model . AddGeneralMultiplicationEquality ( compromising_documents , non_negative_amalgamy , non_negative_menace , non_negative_antiquity )
value_remainder = model . NewIntVar ( 0 , 49 , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_BIRD . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 50 )
model . Add ( primary_revenue == value - value_remainder + 50 ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_BIRD ] )
model . Add ( secondary_revenue == 50 * compromising_documents ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_BIRD ] )
model . Add ( difficulty_level == 0 ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_BIRD ] )
# The indirection is necessary for applying an enforcement literal
derived_exhaustion = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_BIRD . name , ' derived exhaustion ' ) )
model . AddDivisionEquality ( derived_exhaustion , compromising_documents , 100 )
model . Add ( added_exhaustion == derived_exhaustion ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_BIRD ] )
del non_negative_amalgamy , non_negative_menace , non_negative_antiquity , compromising_documents , value_remainder , derived_exhaustion
2021-07-06 16:25:15 +00:00
# The Trifling Diplomat - Fish
model . AddLinearExpressionInDomain ( skeleton_in_progress , cp_model . Domain . FromFlatIntervals ( [ 190 , 199 ] ) ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_FISH ] )
2021-06-29 20:56:42 +00:00
2021-07-06 16:25:15 +00:00
non_negative_amalgamy = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_FISH . name , ' non-negative amalgamy ' ) )
2021-06-29 20:56:42 +00:00
model . AddMaxEquality ( non_negative_amalgamy , [ amalgamy , 0 ] )
2021-07-06 16:25:15 +00:00
non_negative_menace = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_FISH . name , ' non-negative menace ' ) )
2021-06-29 20:56:42 +00:00
model . AddMaxEquality ( non_negative_menace , [ menace , 0 ] )
2021-07-06 16:25:15 +00:00
non_negative_antiquity = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_FISH . name , ' non-negative antiquity ' ) )
2021-06-29 20:56:42 +00:00
model . AddMaxEquality ( non_negative_antiquity , [ antiquity , 0 ] )
2021-07-06 16:42:20 +00:00
compromising_documents = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_FISH . name , ' compromising documents ' ) )
2021-06-29 20:56:42 +00:00
model . AddGeneralMultiplicationEquality ( compromising_documents , non_negative_amalgamy , non_negative_menace , non_negative_antiquity )
2021-07-06 16:25:15 +00:00
value_remainder = model . NewIntVar ( 0 , 49 , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_FISH . name , ' value remainder ' ) )
2021-06-29 20:56:42 +00:00
model . AddModuloEquality ( value_remainder , value , 50 )
2021-07-06 16:25:15 +00:00
model . Add ( primary_revenue == value - value_remainder + 50 ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_FISH ] )
model . Add ( secondary_revenue == 50 * compromising_documents ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_FISH ] )
2021-06-29 20:56:42 +00:00
2021-07-06 16:25:15 +00:00
model . Add ( difficulty_level == 0 ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_FISH ] )
2021-06-29 20:56:42 +00:00
# The indirection is necessary for applying an enforcement literal
2021-07-06 16:25:15 +00:00
derived_exhaustion = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_FISH . name , ' derived exhaustion ' ) )
2021-06-29 20:56:42 +00:00
model . AddDivisionEquality ( derived_exhaustion , compromising_documents , 100 )
2021-07-06 16:25:15 +00:00
model . Add ( added_exhaustion == derived_exhaustion ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_FISH ] )
2021-06-29 20:56:42 +00:00
del non_negative_amalgamy , non_negative_menace , non_negative_antiquity , compromising_documents , value_remainder , derived_exhaustion
2021-07-14 15:39:20 +00:00
# The Trifling Diplomat - Insect
model . AddLinearExpressionInDomain ( skeleton_in_progress , cp_model . Domain . FromFlatIntervals ( [ 210 , 219 ] ) ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_INSECT ] )
non_negative_amalgamy = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_INSECT . name , ' non-negative amalgamy ' ) )
model . AddMaxEquality ( non_negative_amalgamy , [ amalgamy , 0 ] )
non_negative_menace = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_INSECT . name , ' non-negative menace ' ) )
model . AddMaxEquality ( non_negative_menace , [ menace , 0 ] )
non_negative_antiquity = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_INSECT . name , ' non-negative antiquity ' ) )
model . AddMaxEquality ( non_negative_antiquity , [ antiquity , 0 ] )
compromising_documents = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_INSECT . name , ' compromising documents ' ) )
model . AddGeneralMultiplicationEquality ( compromising_documents , non_negative_amalgamy , non_negative_menace , non_negative_antiquity )
value_remainder = model . NewIntVar ( 0 , 49 , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_INSECT . name , ' value remainder ' ) )
model . AddModuloEquality ( value_remainder , value , 50 )
model . Add ( primary_revenue == value - value_remainder + 50 ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_INSECT ] )
model . Add ( secondary_revenue == 50 * compromising_documents ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_INSECT ] )
model . Add ( difficulty_level == 0 ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_INSECT ] )
# The indirection is necessary for applying an enforcement literal
derived_exhaustion = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' {} : {} ' . format ( Buyer . THE_TRIFLING_DIPLOMAT_INSECT . name , ' derived exhaustion ' ) )
model . AddDivisionEquality ( derived_exhaustion , compromising_documents , 100 )
model . Add ( added_exhaustion == derived_exhaustion ) . OnlyEnforceIf ( actions [ Buyer . THE_TRIFLING_DIPLOMAT_INSECT ] )
del non_negative_amalgamy , non_negative_menace , non_negative_antiquity , compromising_documents , value_remainder , derived_exhaustion
2021-06-08 22:28:15 +00:00
# Maximize profit margin
net_profit = model . NewIntVar ( cp_model . INT32_MIN , cp_model . INT32_MAX , ' net profit ' )
model . Add ( net_profit == total_revenue - cost )
# This is necessary to preserve some degree of precision after dividing
multiplied_net_profit = model . NewIntVar ( cp_model . INT32_MIN * PROFIT_MARGIN_MULTIPLIER , cp_model . INT32_MAX * PROFIT_MARGIN_MULTIPLIER , ' multiplied net profit ' )
model . AddMultiplicationEquality ( multiplied_net_profit , [ net_profit , PROFIT_MARGIN_MULTIPLIER ] )
absolute_multiplied_net_profit = model . NewIntVar ( 0 , cp_model . INT32_MAX * PROFIT_MARGIN_MULTIPLIER , ' absolute multiplied net profit ' )
model . AddAbsEquality ( absolute_multiplied_net_profit , multiplied_net_profit )
absolute_profit_margin = model . NewIntVar ( cp_model . INT32_MIN * PROFIT_MARGIN_MULTIPLIER , cp_model . INT32_MAX * PROFIT_MARGIN_MULTIPLIER , ' absolute profit margin ' )
model . AddDivisionEquality ( absolute_profit_margin , absolute_multiplied_net_profit , total_revenue )
profit_margin = model . NewIntVar ( cp_model . INT32_MIN * PROFIT_MARGIN_MULTIPLIER , cp_model . INT32_MAX * PROFIT_MARGIN_MULTIPLIER , ' profit margin ' )
positive_net_profit = model . NewIntermediateBoolVar ( ' positive net profit ' , net_profit , cp_model . Domain . FromFlatIntervals ( [ 0 , cp_model . INT_MAX ] ) )
model . Add ( profit_margin == absolute_profit_margin ) . OnlyEnforceIf ( positive_net_profit )
model . Add ( profit_margin == absolute_profit_margin * - 1 ) . OnlyEnforceIf ( positive_net_profit . Not ( ) )
del multiplied_net_profit , absolute_multiplied_net_profit , absolute_profit_margin , positive_net_profit
2021-06-13 22:37:39 +00:00
2021-06-08 22:28:15 +00:00
model . Maximize ( profit_margin )
2021-06-15 19:13:07 +00:00
class SkeletonPrinter ( cp_model . CpSolverSolutionCallback ) :
2021-06-18 19:44:30 +00:00
""" A class that prints the steps that comprise a skeleton as well as relevant attributes. """
2021-06-15 19:13:07 +00:00
def __init__ ( self ) :
cp_model . CpSolverSolutionCallback . __init__ ( self )
self . __solution_count = 0
def PrintableSolution ( self , solver = None ) :
2021-06-18 19:44:30 +00:00
""" Print the latest solution of a provided solver. """
2021-06-15 19:13:07 +00:00
output = " "
# Allows use as a callback
if solver is None :
solver = self
for action in actions . keys ( ) :
for _ in range ( int ( solver . Value ( actions [ action ] ) ) ) :
output + = str ( action ) + " \n "
output + = " \n Profit: £ {:,.2f} \n " . format ( solver . Value ( net_profit ) / 100 )
output + = " Profit Margin: {:+,.2%} \n " . format ( solver . Value ( profit_margin ) / PROFIT_MARGIN_MULTIPLIER )
output + = " \n Total Revenue: £ {:,.2f} \n " . format ( solver . Value ( total_revenue ) / 100 )
output + = " Primary Revenue: £ {:,.2f} \n " . format ( solver . Value ( primary_revenue ) / 100 )
output + = " Secondary Revenue: £ {:,.2f} \n " . format ( solver . Value ( secondary_revenue ) / 100 )
output + = " \n Cost: £ {:,.2f} \n " . format ( solver . Value ( cost ) / 100 )
output + = " \n Value: £ {:,.2f} \n " . format ( solver . Value ( value ) / 100 )
output + = " Amalgamy: {:n} \n " . format ( solver . Value ( amalgamy ) )
output + = " Antiquity: {:n} \n " . format ( solver . Value ( antiquity ) )
output + = " Menace: {:n} \n " . format ( solver . Value ( menace ) )
output + = " Counter-Church: {:n} \n " . format ( solver . Value ( counter_church ) )
output + = " Implausibility: {:n} \n " . format ( solver . Value ( implausibility ) )
output + = " \n Exhaustion: {:n} " . format ( solver . Value ( exhaustion ) )
return output
def OnSolutionCallback ( self ) :
self . __solution_count + = 1
2021-06-15 21:50:28 +00:00
# Prints current solution to window
stdscr . clear ( )
stdscr . addstr ( self . PrintableSolution ( ) )
stdscr . addstr ( stdscr . getmaxyx ( ) [ 0 ] - 1 , 0 , " Skeleton # {:n} " . format ( self . __solution_count ) )
stdscr . refresh ( )
2021-06-15 19:13:07 +00:00
def SolutionCount ( self ) :
return self . __solution_count
printer = SkeletonPrinter ( )
2021-06-08 22:28:15 +00:00
solver = cp_model . CpSolver ( )
2021-06-18 21:18:40 +00:00
solver . parameters . num_search_workers = workers
2021-06-16 16:32:05 +00:00
solver . parameters . max_time_in_seconds = time_limit
2021-06-08 22:28:15 +00:00
2021-06-15 21:50:28 +00:00
# There's no window in verbose mode
if stdscr is None :
solver . parameters . log_search_progress = True
solver . Solve ( model )
else :
solver . SolveWithSolutionCallback ( model , printer )
status = solver . StatusName ( )
2021-06-18 18:48:20 +00:00
if status == ' INFEASIBLE ' :
2021-06-08 22:28:15 +00:00
raise RuntimeError ( " There is no satisfactory skeleton. " )
2021-06-18 18:48:20 +00:00
elif status == ' FEASIBLE ' :
2021-06-08 22:28:15 +00:00
print ( " WARNING: skeleton may be suboptimal. " )
2021-06-18 18:48:20 +00:00
elif status != ' OPTIMAL ' :
2021-06-08 22:28:15 +00:00
raise RuntimeError ( " Unknown status returned: {} . " . format ( status ) )
2021-06-15 21:50:28 +00:00
return printer . PrintableSolution ( solver )