2021-06-18 20:28:56 +00:00
""" Use constraint programming to devise the optimal skeleton at the Bone Market in Fallen London. """
2021-07-06 17:05:10 +00:00
__all__ = [ ' Declaration ' , ' DiplomatFascination ' , ' Fluctuation ' , ' OccasionalBuyer ' , ' Solve ' ]
2021-06-18 20:28:56 +00:00
__author__ = " Jeremy Saklad "
2021-06-14 00:40:11 +00:00
import argparse
2021-06-15 21:50:28 +00:00
import curses
2021-06-18 20:08:28 +00:00
from enum import Enum
from functools import reduce
from os import cpu_count
2021-06-08 22:28:15 +00:00
from ortools . sat . python import cp_model
# 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
2021-06-18 20:08:28 +00:00
class Cost ( Enum ) :
2021-06-18 19:44:30 +00:00
""" The number of pennies needed to produce a quality. """
2021-06-08 23:55:56 +00:00
# This is your baseline EPA: the pennies you could generate using an action for a generic grind.
ACTION = 400
2021-06-09 00:55:30 +00:00
# Antique Mystery
ANTIQUE_MYSTERY = 1250
2021-06-11 19:04:48 +00:00
# Favours: Bohemians
# Various opportunity cards
BOHEMIAN_FAVOURS = ACTION
2021-06-09 00:55:30 +00:00
# Bone Fragment
BONE_FRAGMENT = 1
# Cartographer's Hoard
CARTOGRAPHERS_HOARD = 31250
2021-06-11 19:55:55 +00:00
# Favours: The Church
# Various opportunity cards
CHURCH_FAVOURS = ACTION
2021-06-09 00:55:30 +00:00
# Collection Note: There's a 'Package' in London
# Station VIII Lab
COLLECTION_NOTE = ACTION
# Volume of Collated Research
COLLATED_RESEARCH = 250
2021-06-11 19:04:48 +00:00
# Deep-Zee Catch
# Spear-fishing at the bottom of the Evenlode, 7 at a time
DEEP_ZEE_CATCH = ACTION / 7
# Crustacean Pincer
# Ealing Gardens Butcher, 2 at a time
CRUSTACEAN_PINCER = ( ACTION + DEEP_ZEE_CATCH ) / 2
2021-06-11 19:55:55 +00:00
# Femur of a Surface Deer
# Dumbwaiter of Balmoral, 25 at a time
DEER_FEMUR = ACTION / 25
2021-06-09 17:56:24 +00:00
# Favours: The Docks
# Various opportunity cards
DOCK_FAVOURS = ACTION
2021-06-13 19:27:53 +00:00
# Extraordinary Implication
EXTRAORDINARY_IMPLICATION = 250
2021-06-09 17:56:24 +00:00
# Eyeless Skull
# No consistent source
2021-06-12 20:51:56 +00:00
EYELESS_SKULL = cp_model . INT32_MAX / 2
2021-06-09 17:56:24 +00:00
2021-06-11 19:55:55 +00:00
# Holy Relic of the Thigh of Saint Fiacre
# Jericho Locks statue, 2 at a time
FIACRE_THIGH = ( ACTION + 4 * CHURCH_FAVOURS ) / 2
# Fin Bones, Collected
# Hunt and dissect Pinewood Shark, 40 at a time
FIN_BONES = ( 11 * ACTION ) / 40
# Amber-Crusted Fin
# Helicon House
AMBER_FIN = ACTION + 10 * FIN_BONES
2021-06-09 00:55:30 +00:00
# Five-Pointed Ribcage
# Upwards
FIVE_POINTED_RIBCAGE = 9 * ACTION + CARTOGRAPHERS_HOARD
2021-06-09 17:56:24 +00:00
# Esteem of the Guild
# Jericho Parade, 2 at a time
GUILD_ESTEEM = ( ACTION + 5 * DOCK_FAVOURS ) / 2
# Skull in Coral
# Persephone, 1-2 at a time
CORAL_SKULL = 1.5 * ( 2 * ACTION + 3 * GUILD_ESTEEM )
2021-06-09 00:55:30 +00:00
# Headless Skeleton
# These are accumulated while acquiring other qualities.
HEADLESS_SKELETON = 0
2021-06-09 17:56:24 +00:00
# Hinterland Scrip
HINTERLAND_SCRIP = 50
2021-06-11 19:04:48 +00:00
# Fossilised Forelimb
# Anning and Daughters
2021-06-17 13:30:48 +00:00
FOSSILISED_FORELIMB = 55 * HINTERLAND_SCRIP
2021-06-11 19:04:48 +00:00
2021-06-11 19:55:55 +00:00
# Hedonist
# Handsome Townhouse, 3cp at a time
HEDONIST_CP = ACTION / 3
2021-06-11 19:04:48 +00:00
# Human Arm
# These are accumulated while acquiring other qualities.
HUMAN_ARM = 0
2021-06-13 19:27:53 +00:00
# Incisive Observation
INCISIVE_OBSERVATION = 50
2021-06-09 17:56:24 +00:00
# Crate of Incorruptible Biscuits
INCORRUPTIBLE_BISCUITS = 250
# Inkling of Identity
INKLING_OF_IDENTITY = 10
# A Custom-Engraved Skull
# Feast of the Exceptional Rose, sent by one player and accepted by another
ENGRAVED_SKULL = 2 * ACTION + 200 * INKLING_OF_IDENTITY
2021-06-11 19:04:48 +00:00
# Ivory Humerus
# Ealing Gardens statue, 2 at a time
IVORY_HUMERUS = ( ACTION + 4 * BOHEMIAN_FAVOURS ) / 2
2021-06-13 15:39:13 +00:00
# Jade Fragment
JADE_FRAGMENT = 1
2021-06-11 19:55:55 +00:00
# Femur of a Jurassic Beast
# Brawling for yourself, large Bone Market crate, 12 at a time
JURASSIC_FEMUR = ( 10 * ACTION ) / 12
2021-06-11 19:04:48 +00:00
# Knotted Humerus
# These are accumulated while acquiring other qualities.
KNOTTED_HUMERUS = 0
2021-06-09 00:55:30 +00:00
# Nevercold Brass Sliver
NEVERCOLD_BRASS = 1
2021-06-12 20:51:56 +00:00
# Obsidian Chitin Tail
# No consistent source
OBSIDIAN_TAIL = cp_model . INT32_MAX / 2
2021-06-11 19:55:55 +00:00
# Parabolan Orange-apple
# Parabolan Base-camp, electricity and hedonism, 2 at a time
ORANGE_APPLE = ( 2 * ACTION + 100 * BONE_FRAGMENT + 21 * HEDONIST_CP ) / 2
# Ivory Femur
# Bohemian Sculptress
IVORY_FEMUR = ACTION + 750 * BONE_FRAGMENT + 3 * ORANGE_APPLE
2021-06-13 17:49:36 +00:00
# Penny
PENNY = 1
# Bright Brass Skull
# Merrigans Exchange
BRASS_SKULL = 6250 * PENNY
2021-06-09 17:56:24 +00:00
# Pentagrammic Skull
# Upwards
PENTAGRAMMIC_SKULL = 9 * ACTION
# Hand-picked Peppercaps
PEPPERCAPS = HINTERLAND_SCRIP
2021-06-13 19:27:53 +00:00
# Revisionist Historical Narrative
# Waswood
REVISIONIST_NARRATIVE = ACTION + 4 * EXTRAORDINARY_IMPLICATION + INCISIVE_OBSERVATION
2021-06-09 00:55:30 +00:00
# Knob of Scintillack
SCINTILLACK = 250
# Searing Enigma
SEARING_ENIGMA = 6250
2021-06-09 17:56:24 +00:00
# Carved Ball of Stygian Ivory
STYGIAN_IVORY = 250
2021-06-09 00:55:30 +00:00
# Preserved Surface Blooms
SURFACE_BLOOMS = 250
# Consignment of Scintillack Snuff
# Laboratory Manufacturing
SCINTILLACK_SNUFF = ( ACTION + 8 * SCINTILLACK + SURFACE_BLOOMS ) / 2
# Elation at Feline Oration
# Pinnock
ELATION_AT_FELINE_ORATION = ACTION + 2 * ANTIQUE_MYSTERY + COLLECTION_NOTE + 2 * SCINTILLACK_SNUFF
# Oil of Companionship
# Station VIII Lab
OIL_OF_COMPANIONSHIP = ACTION + ELATION_AT_FELINE_ORATION
2021-06-08 23:55:56 +00:00
# Survey of the Neath's Bones
# Laboratory Research
SURVEY = 6 * ACTION / 25
2021-06-12 20:51:56 +00:00
# Plaster Tail Bones
# Carpenter's Granddaughter, 2 at a time
PLASTER_TAIL_BONES = ( ACTION + 10 * SURVEY ) / 2
2021-06-09 00:55:30 +00:00
# Human Ribcage
# Ealing Gardens
HUMAN_RIBCAGE = ACTION + 15 * SURVEY
# Palaeontological Discovery
# Plain of Thirsty Grasses
PALAEONTOLOGICAL_DISCOVERY = ( ACTION + 140 * SURVEY ) / 6
2021-06-11 19:55:55 +00:00
# Helical Thighbone
# Results of Excavation, 6 at a time
HELICAL_THIGH = ( 2 * PALAEONTOLOGICAL_DISCOVERY ) / 6
2021-06-09 00:55:30 +00:00
# Leviathan Frame
# Results of Excavation
LEVIATHAN_FRAME = 25 * PALAEONTOLOGICAL_DISCOVERY
# Thorned Ribcage
# Iron-Toothed Terror Bird
THORNED_RIBCAGE = 6 * ACTION
# Flourishing Ribcage
# Helicon House
FLOURISHING_RIBCAGE = ACTION + HUMAN_RIBCAGE + THORNED_RIBCAGE
2021-06-09 17:56:24 +00:00
# Time Remaining in the Woods
2021-06-17 13:30:48 +00:00
# Compel Ghillie, 7 at a time
TIME_REMAINING_IN_THE_WOODS = ( ACTION + 4 * COLLATED_RESEARCH ) / 7
2021-06-09 17:56:24 +00:00
2021-06-12 23:58:59 +00:00
# Observation: Red Deer
# Balmoral Woods
2021-06-17 13:30:48 +00:00
DEER_OBSERVATION = 13 * ACTION + 12 * TIME_REMAINING_IN_THE_WOODS
2021-06-12 23:58:59 +00:00
# Mammoth Ribcage
# Keeper of the Marigold Menagerie
MAMMOTH_RIBCAGE = ACTION + DEER_OBSERVATION
2021-06-09 17:56:24 +00:00
# Observation: Fox
# Balmoral Woods
FOX_OBSERVATION = 10 * ACTION + 8 * TIME_REMAINING_IN_THE_WOODS
# Doubled Skull
# Keeper of the Marigold Menagerie
DOUBLED_SKULL = ACTION + FOX_OBSERVATION
2021-06-12 23:58:59 +00:00
# Observation: Grouse
# Balmoral Woods
2021-06-17 13:30:48 +00:00
GROUSE_OBSERVATION = 9 * ACTION + 8 * TIME_REMAINING_IN_THE_WOODS
2021-06-12 23:58:59 +00:00
# Skeleton with Seven Necks
# Keeper of the Marigold Menagerie
SKELETON_WITH_SEVEN_NECKS = ACTION + GROUSE_OBSERVATION
2021-06-09 00:55:30 +00:00
# Nodule of Trembling Amber
TREMBLING_AMBER = 1250
# Ribcage with a Bouquet of Eight Spines
# Helicon House
2021-06-19 12:33:46 +00:00
RIBCAGE_WITH_EIGHT_SPINES = ACTION + 3 * SEARING_ENIGMA + SKELETON_WITH_SEVEN_NECKS + THORNED_RIBCAGE + 3 * TREMBLING_AMBER
2021-06-09 00:55:30 +00:00
2021-06-09 17:56:24 +00:00
# Rubbery Skull
# Flute Street, including travel due to quality cap
RUBBERY_SKULL = 25 * ACTION
2021-06-09 00:55:30 +00:00
# Rumour of the Upper River
RUMOUR_OF_THE_UPPER_RIVER = 250
2021-06-12 20:51:56 +00:00
# Jet Black Stinger
# Hunting with Sophia's, 5 at a time
BLACK_STINGER = ( ACTION + 5 * RUMOUR_OF_THE_UPPER_RIVER ) / 5
2021-06-09 00:55:30 +00:00
# Prismatic Frame
# Expedition at Station VIII
PRISMATIC_FRAME = ACTION + OIL_OF_COMPANIONSHIP + 98 * RUMOUR_OF_THE_UPPER_RIVER
2021-06-11 19:55:55 +00:00
# Unidentified Thigh Bone
# These are accumulated while acquiring other qualities.
UNIDENTIFIED_THIGH = 0
2021-06-09 00:55:30 +00:00
# Nodule of Warm Amber
WARM_AMBER = 10
2021-06-11 19:39:55 +00:00
# Albatross Wing
# Ealing Gardens Butcher, 2 at a time
ALBATROSS_WING = ( ACTION + 2000 * BONE_FRAGMENT + 25 * WARM_AMBER ) / 2
# Bat Wing
# Ealing Gardens Butcher, 2 at a time
BAT_WING = ( ACTION + 100 * BONE_FRAGMENT + 2 * WARM_AMBER ) / 2
2021-06-09 17:56:24 +00:00
# Horned Skull
# Ealing Gardens Butcher
HORNED_SKULL = ACTION + 1000 * BONE_FRAGMENT + 5 * WARM_AMBER
# Plated Skull
# Ealing Gardens Butcher
PLATED_SKULL = ACTION + 1750 * BONE_FRAGMENT + INCORRUPTIBLE_BISCUITS + 25 * WARM_AMBER
# Sabre-toothed Skull
# Ealing Gardens Butcher
SABRE_TOOTHED_SKULL = ACTION + 4900 * BONE_FRAGMENT + 125 * WARM_AMBER
2021-06-11 19:39:55 +00:00
# Wing of a Young Terror Bird
# Ealing Gardens Butcher, 2 at a time
TERROR_BIRD_WING = ( ACTION + 100 * BONE_FRAGMENT + 25 * WARM_AMBER ) / 2
2021-06-12 20:51:56 +00:00
# Tomb-Lion's Tail
# Ealing Gardens Butcher
TOMB_LION_TAIL = ACTION + 200 * BONE_FRAGMENT + 2 * WARM_AMBER
2021-06-09 00:55:30 +00:00
# Warbler Skeleton
# Ealing Gardens Butcher
WARBLER_SKELETON = ACTION + 130 * BONE_FRAGMENT + 2 * WARM_AMBER
2021-06-11 19:55:55 +00:00
# Withered Tentacle
# Helicon House, 3 at a time
WITHERED_TENTACLE = ( ACTION + 5 * WARM_AMBER ) / 3
2021-06-08 23:55:56 +00:00
2021-06-08 22:28:15 +00:00
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
class Action :
2021-06-18 19:44:30 +00:00
""" An action that affects a skeleton ' s qualities. """
2021-06-08 22:49:45 +00:00
def __init__ ( self , name , cost , torso_style = None , value = 0 , skulls_needed = 0 , limbs_needed = 0 , tails_needed = 0 , skulls = 0 , arms = 0 , legs = 0 , tails = 0 , wings = 0 , fins = 0 , tentacles = 0 , amalgamy = 0 , antiquity = 0 , menace = 0 , implausibility = 0 , counter_church = 0 , exhaustion = 0 ) :
2021-06-08 22:28:15 +00:00
self . name = name
# Cost in pennies of using this action, including the value of the actions spent
self . cost = cost
2021-06-08 22:49:45 +00:00
# Skeleton: Torso Style
self . torso_style = torso_style
2021-06-08 22:28:15 +00:00
# Approximate Value of Your Skeleton in Pennies
self . value = value
# Skeleton: Skulls Needed
self . skulls_needed = skulls_needed
# Skeleton: Limbs Needed
self . limbs_needed = limbs_needed
# Skeleton: Tails Needed
self . tails_needed = tails_needed
# Skeleton: Skulls
self . skulls = skulls
# Skeleton: Arms
self . arms = arms
# Skeleton: Legs
self . legs = legs
# Skeleton: Tails
self . tails = tails
# Skeleton: Wings
self . wings = wings
# Skeleton: Fins
self . fins = fins
# Skeleton: Tentacles
self . tentacles = tentacles
# Skeleton: Amalgamy
self . amalgamy = amalgamy
# Skeleton: Antiquity
self . antiquity = antiquity
# Skeleton: Menace
self . menace = menace
# Skeleton: Self-Evident Implausibility
self . implausibility = implausibility
# Skeleton: Support for a Counter-church Theology
self . counter_church = counter_church
# Bone Market Exhaustion
self . exhaustion = exhaustion
def __str__ ( self ) :
return str ( self . name )
2021-06-18 20:08:28 +00:00
class Torso ( Enum ) :
2021-06-18 19:44:30 +00:00
""" An action that initiates a skeleton. """
2021-06-09 00:55:30 +00:00
HEADLESS_HUMANOID = Action (
" Reassemble your Headless Humanoid " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . HEADLESS_SKELETON . value ,
2021-06-09 00:55:30 +00:00
torso_style = 10 ,
value = 250 ,
skulls_needed = 1 ,
arms = 2 ,
legs = 2
)
2021-06-08 23:23:30 +00:00
2021-06-09 00:55:30 +00:00
# Licentiate
2021-06-09 15:29:56 +00:00
# VICTIM_SKELETON = Action(
2021-06-09 00:55:30 +00:00
# "Supply a skeleton of your own",
2021-06-13 17:43:52 +00:00
# cost = Cost.ACTION.value,
2021-06-09 00:55:30 +00:00
# torso_style = 10,
# value = 250,
# skulls_needed = 1,
# arms = 2,
# legs = 2
# )
HUMAN_RIBCAGE = Action (
" Build on the Human Ribcage " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . HUMAN_RIBCAGE . value ,
2021-06-09 00:55:30 +00:00
torso_style = 15 ,
value = 1250 ,
skulls_needed = 1 ,
limbs_needed = 4
)
THORNED_RIBCAGE = Action (
" Make something of your Thorned Ribcage " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . THORNED_RIBCAGE . value ,
2021-06-09 00:55:30 +00:00
torso_style = 20 ,
value = 1250 ,
skulls_needed = 1 ,
limbs_needed = 4 ,
tails_needed = 1 ,
amalgamy = 1 ,
menace = 1
)
SKELETON_WITH_SEVEN_NECKS = Action (
" Build on the Skeleton with Seven Necks " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . SKELETON_WITH_SEVEN_NECKS . value ,
2021-06-09 00:55:30 +00:00
torso_style = 30 ,
value = 6250 ,
skulls_needed = 7 ,
limbs_needed = 2 ,
legs = 2 ,
amalgamy = 2 ,
menace = 1
)
FLOURISHING_RIBCAGE = Action (
" Build on the Flourishing Ribcage " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . FLOURISHING_RIBCAGE . value ,
2021-06-09 00:55:30 +00:00
torso_style = 40 ,
value = 1250 ,
skulls_needed = 2 ,
limbs_needed = 6 ,
tails_needed = 1 ,
amalgamy = 2
)
MAMMOTH_RIBCAGE = Action (
" Build on the Mammoth Ribcage " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . MAMMOTH_RIBCAGE . value ,
2021-06-09 00:55:30 +00:00
torso_style = 50 ,
value = 6250 ,
skulls_needed = 1 ,
limbs_needed = 4 ,
tails_needed = 1 ,
antiquity = 2
)
RIBCAGE_WITH_A_BOUQUET_OF_EIGHT_SPINES = Action (
" Build on the Ribcage with the Eight Spines " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . RIBCAGE_WITH_EIGHT_SPINES . value ,
2021-06-09 00:55:30 +00:00
torso_style = 60 ,
value = 31250 ,
skulls_needed = 8 ,
limbs_needed = 4 ,
tails_needed = 1 ,
amalgamy = 1 ,
menace = 2
)
2021-06-18 18:47:09 +00:00
LEVIATHAN_FRAME = Action (
" Build on the Leviathan Frame " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . LEVIATHAN_FRAME . value ,
2021-06-09 00:55:30 +00:00
torso_style = 70 ,
value = 31250 ,
skulls_needed = 1 ,
limbs_needed = 2 ,
tails = 1 ,
antiquity = 1 ,
menace = 1
)
PRISMATIC_FRAME = Action (
" Build on the Prismatic Frame " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . PRISMATIC_FRAME . value ,
2021-06-09 00:55:30 +00:00
torso_style = 80 ,
value = 31250 ,
skulls_needed = 3 ,
limbs_needed = 3 ,
tails_needed = 3 ,
amalgamy = 2 ,
antiquity = 2
)
FIVE_POINTED_FRAME = Action (
" Build on the Five-Pointed Frame " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . FIVE_POINTED_RIBCAGE . value ,
2021-06-09 00:55:30 +00:00
torso_style = 100 ,
value = 31250 ,
skulls_needed = 5 ,
limbs_needed = 5 ,
amalgamy = 2 ,
menace = 1
)
2021-06-08 23:23:30 +00:00
def __str__ ( self ) :
return str ( self . value )
2021-06-18 20:08:28 +00:00
class Skull ( Enum ) :
2021-06-18 19:44:30 +00:00
""" An action that is taken immediately after starting a skeleton. """
2021-06-09 17:56:24 +00:00
BAPTIST_SKULL = Action (
" Duplicate the skull of John the Baptist, if you can call that a skull " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + 500 * Cost . BONE_FRAGMENT . value + 10 * Cost . PEPPERCAPS . value ,
2021-06-17 13:30:48 +00:00
value = 1250 ,
2021-06-09 17:56:24 +00:00
skulls_needed = - 1 ,
skulls = 1 ,
2021-06-17 13:30:48 +00:00
counter_church = 1
2021-06-09 17:56:24 +00:00
)
2021-06-09 15:29:56 +00:00
2021-06-09 17:56:24 +00:00
BRASS_SKULL = Action (
" Affix a Bright Brass Skull to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . BRASS_SKULL . value + 200 * Cost . NEVERCOLD_BRASS . value ,
2021-06-09 17:56:24 +00:00
value = 6500 ,
skulls_needed = - 1 ,
skulls = 1 ,
implausibility = 2
)
2021-06-09 15:29:56 +00:00
2021-06-09 17:56:24 +00:00
CORAL_SKULL = Action (
" Affix a Skull in Coral to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . CORAL_SKULL . value + Cost . SCINTILLACK . value ,
2021-06-09 17:56:24 +00:00
value = 1750 ,
skulls_needed = - 1 ,
skulls = 1 ,
amalgamy = 2
)
2021-06-09 15:29:56 +00:00
2021-06-09 17:56:24 +00:00
DOUBLED_SKULL = Action (
" Affix a Doubled Skull to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . DOUBLED_SKULL . value ,
2021-06-09 17:56:24 +00:00
value = 6250 ,
skulls_needed = - 1 ,
skulls = 2 ,
amalgamy = 1 ,
antiquity = 2
)
2021-06-09 15:29:56 +00:00
2021-06-09 17:56:24 +00:00
# Adds Exhaustion
# ENGRAVED_SKULL = Action(
# "Affix a Custom-Engraved Skull to your (Skeleton Type)",
2021-06-13 17:43:52 +00:00
# cost = Cost.ACTION.value + Cost.ENGRAVED_SKULL.value,
2021-06-09 17:56:24 +00:00
# value = 10000,
# skulls_needed = -1,
# skulls = 1,
# exhaustion = 2
# )
EYELESS_SKULL = Action (
" Affix an Eyeless Skull to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . EYELESS_SKULL . value ,
2021-06-09 17:56:24 +00:00
value = 3000 ,
skulls_needed = - 1 ,
skulls = 1 ,
menace = 2
)
2021-06-09 15:29:56 +00:00
2021-06-09 17:56:24 +00:00
HORNED_SKULL = Action (
" Affix a Horned Skull to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . HORNED_SKULL . value ,
2021-06-09 17:56:24 +00:00
value = 1250 ,
skulls_needed = - 1 ,
skulls = 1 ,
antiquity = 1 ,
menace = 2
)
2021-06-09 15:29:56 +00:00
2021-06-09 17:56:24 +00:00
# Seeking the Name of Mr. Eaten
# OWN_SKULL = Action(
# "Duplicate your own skull and affix it here",
2021-06-13 17:43:52 +00:00
# cost = Cost.ACTION.value + 1000*Cost.BONE_FRAGMENT.value,
2021-06-09 17:56:24 +00:00
# value = -250,
# skulls_needed = -1,
# skulls = 1
# )
PENTAGRAMMIC_SKULL = Action (
" Affix a Pentagrammic Skull to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . PENTAGRAMMIC_SKULL . value ,
2021-06-09 17:56:24 +00:00
value = 1250 ,
skulls_needed = - 1 ,
skulls = 1 ,
amalgamy = 2 ,
menace = 1
)
2021-06-09 15:29:56 +00:00
2021-06-09 17:56:24 +00:00
PLATED_SKULL = Action (
" Affix a Plated Skull to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . PLATED_SKULL . value ,
2021-06-09 17:56:24 +00:00
value = 2500 ,
skulls_needed = - 1 ,
skulls = 1 ,
menace = 2
)
2021-06-09 15:29:56 +00:00
2021-06-09 17:56:24 +00:00
RUBBERY_SKULL = Action (
" Affix a Rubbery Skull to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . RUBBERY_SKULL . value ,
2021-06-09 17:56:24 +00:00
value = 600 ,
skulls_needed = - 1 ,
skulls = 1 ,
amalgamy = 1
)
2021-06-09 15:29:56 +00:00
2021-06-09 17:56:24 +00:00
SABRE_TOOTHED_SKULL = Action (
" Affix a Sabre-toothed Skull to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . SABRE_TOOTHED_SKULL . value ,
2021-06-09 17:56:24 +00:00
value = 6250 ,
skulls_needed = - 1 ,
skulls = 1 ,
antiquity = 1 ,
menace = 1
)
2021-06-09 15:29:56 +00:00
2021-06-09 17:56:24 +00:00
STYGIAN_IVORY = Action (
" Use a Carved Ball of Stygian Ivory to cap off your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . STYGIAN_IVORY . value ,
2021-06-09 17:56:24 +00:00
value = 250 ,
skulls_needed = - 1
)
2021-06-09 15:29:56 +00:00
2021-06-09 17:56:24 +00:00
VAKE_SKULL = Action (
" Duplicate the Vake ' s skull and use it to decorate your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + 6000 * Cost . BONE_FRAGMENT . value ,
2021-06-09 17:56:24 +00:00
value = 6500 ,
skulls_needed = - 1 ,
skulls = 1 ,
menace = 3
)
2021-06-09 15:29:56 +00:00
2021-06-09 17:56:24 +00:00
# Licentiate
# VICTIM_SKULL = Action(
# "Cap this with a victim’ s skull",
2021-06-13 17:43:52 +00:00
# cost = Cost.ACTION.value,
2021-06-09 17:56:24 +00:00
# value = 250,
# skulls_needed = -1,
# skulls = 1
# )
2021-06-09 15:29:56 +00:00
def __str__ ( self ) :
return str ( self . value )
2021-06-18 20:08:28 +00:00
class Appendage ( Enum ) :
2021-06-18 19:44:30 +00:00
""" An action that is taken once all skulls are added to a skeleton. """
2021-06-11 23:04:21 +00:00
# Cost from this scales with limbs and is partially implemented separately
ADD_JOINTS = Action (
" Add four more joints to your skeleton " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . TREMBLING_AMBER . value ,
2021-06-11 23:04:21 +00:00
limbs_needed = 4 ,
amalgamy = 2
)
2021-06-11 19:39:55 +00:00
ALBATROSS_WING = Action (
" Put an Albatross Wing on your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . ALBATROSS_WING . value ,
2021-06-11 19:39:55 +00:00
value = 1250 ,
limbs_needed = - 1 ,
wings = 1 ,
amalgamy = 1
)
2021-06-11 19:55:55 +00:00
AMBER_FIN = Action (
" Attach the Amber-Crusted Fin to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . AMBER_FIN . value ,
2021-06-11 19:55:55 +00:00
value = 1500 ,
limbs_needed = - 1 ,
fins = 1 ,
amalgamy = 1 ,
menace = 1
)
2021-06-11 19:39:55 +00:00
BAT_WING = Action (
" Add a Bat Wing to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . BAT_WING . value ,
2021-06-11 19:39:55 +00:00
value = 1 ,
limbs_needed = - 1 ,
wings = 1 ,
menace = - 1
)
2021-06-18 18:47:09 +00:00
BLACK_STINGER = Action (
" Apply a Jet Black Stinger to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . BLACK_STINGER . value ,
2021-06-12 20:51:56 +00:00
value = 50 ,
tails_needed = - 1 ,
tails = 1 ,
menace = 2
)
2021-06-11 19:04:48 +00:00
CRUSTACEAN_PINCER = Action (
" Apply a Crustacean Pincer to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . CRUSTACEAN_PINCER . value ,
2021-06-11 19:04:48 +00:00
limbs_needed = - 1 ,
arms = 1 ,
menace = 1
)
2021-06-11 18:43:37 +00:00
2021-06-11 19:55:55 +00:00
DEER_FEMUR = Action (
" Apply the Femur of a Surface Deer to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . DEER_FEMUR . value ,
2021-06-11 19:55:55 +00:00
value = 10 ,
limbs_needed = - 1 ,
legs = 1 ,
menace = - 1
)
# Counter-Church theology from this scales with torso style and is implemented separately
FIACRE_THIGH = Action (
" Affix Saint Fiacre ' s Thigh Relic to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . FIACRE_THIGH . value ,
2021-06-11 19:55:55 +00:00
value = 1250 ,
limbs_needed = - 1 ,
legs = 1
)
FIN_BONES = Action (
" Put Fins on your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . FIN_BONES . value ,
2021-06-11 19:55:55 +00:00
value = 50 ,
limbs_needed = - 1 ,
fins = 1
)
2021-06-11 19:04:48 +00:00
FOSSILISED_FORELIMB = Action (
" Apply a Fossilised Forelimb to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . FOSSILISED_FORELIMB . value ,
2021-06-11 19:04:48 +00:00
value = 2750 ,
limbs_needed = - 1 ,
arms = 1 ,
antiquity = 2
)
2021-06-11 18:43:37 +00:00
2021-06-11 19:55:55 +00:00
HELICAL_THIGH = Action (
" Affix the Helical Thighbone to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . HELICAL_THIGH . value ,
2021-06-11 19:55:55 +00:00
value = 300 ,
limbs_needed = - 1 ,
legs = 1 ,
amalgamy = 2
)
2021-06-11 19:04:48 +00:00
HUMAN_ARM = Action (
" Join a Human Arm to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . HUMAN_ARM . value ,
2021-06-11 19:04:48 +00:00
value = 250 ,
limbs_needed = - 1 ,
arms = 1 ,
menace = - 1
)
2021-06-11 18:43:37 +00:00
2021-06-11 19:55:55 +00:00
IVORY_FEMUR = Action (
" Apply an Ivory Femur to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . IVORY_FEMUR . value ,
2021-06-11 19:55:55 +00:00
value = 6500 ,
limbs_needed = - 1 ,
legs = 1
)
2021-06-11 19:04:48 +00:00
IVORY_HUMERUS = Action (
" Apply an Ivory Humerus to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . IVORY_HUMERUS . value ,
2021-06-11 19:04:48 +00:00
value = 1500 ,
limbs_needed = - 1 ,
arms = 1
)
2021-06-11 18:43:37 +00:00
2021-06-11 19:55:55 +00:00
JURASSIC_THIGH = Action (
" Apply a Jurassic Thigh Bone to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . JURASSIC_FEMUR . value ,
2021-06-11 19:55:55 +00:00
value = 300 ,
limbs_needed = - 1 ,
legs = 1 ,
antiquity = 1
)
2021-06-11 19:04:48 +00:00
KNOTTED_HUMERUS = Action (
" Apply a Knotted Humerus to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . KNOTTED_HUMERUS . value ,
2021-06-17 16:13:48 +00:00
value = 300 ,
2021-06-11 19:04:48 +00:00
limbs_needed = - 1 ,
arms = 1 ,
amalgamy = 1
)
2021-06-11 18:43:37 +00:00
2021-06-12 20:51:56 +00:00
OBSIDIAN_TAIL = Action (
" Apply an Obsidian Chitin Tail to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . OBSIDIAN_TAIL . value ,
2021-06-12 20:51:56 +00:00
value = 500 ,
tails_needed = - 1 ,
tails = 1 ,
amalgamy = 1
)
PLASTER_TAIL_BONES = Action (
" Apply Plaster Tail Bones to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . PLASTER_TAIL_BONES . value ,
2021-06-12 20:51:56 +00:00
value = 250 ,
tails_needed = - 1 ,
tails = 1 ,
implausibility = 1
)
2021-06-11 19:39:55 +00:00
TERROR_BIRD_WING = Action (
" Add the Wing of a Young Terror Bird to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . TERROR_BIRD_WING . value ,
2021-06-11 19:39:55 +00:00
value = 250 ,
limbs_needed = - 1 ,
wings = 1 ,
antiquity = 1 ,
menace = 1
)
2021-06-11 19:34:45 +00:00
2021-06-12 20:51:56 +00:00
TOMB_LION_TAIL = Action (
" Apply a Tomb-Lion ' s Tail to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . TOMB_LION_TAIL . value ,
2021-06-12 20:51:56 +00:00
value = 250 ,
tails_needed = - 1 ,
tails = 1 ,
antiquity = 1
)
2021-06-11 19:55:55 +00:00
UNIDENTIFIED_THIGH = Action (
" Apply an Unidentified Thigh Bone to your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . UNIDENTIFIED_THIGH . value ,
2021-06-11 19:55:55 +00:00
value = 100 ,
limbs_needed = - 1 ,
legs = 1
)
2021-06-12 20:51:56 +00:00
WITHERED_TAIL = Action (
" Apply a Withered Tentacle as a tail on your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . WITHERED_TENTACLE . value ,
2021-06-12 20:51:56 +00:00
value = 250 ,
tails_needed = - 1 ,
tails = 1 ,
antiquity = - 1
)
2021-06-11 19:55:55 +00:00
WITHERED_TENTACLE = Action (
" Put a Withered Tentacle on your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value + Cost . WITHERED_TENTACLE . value ,
2021-06-11 19:55:55 +00:00
value = 250 ,
limbs_needed = - 1 ,
tentacles = 1 ,
antiquity = - 1
)
2021-06-12 20:51:56 +00:00
REMOVE_TAIL = Action (
" Remove the tail from your (Skeleton Type) " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value ,
2021-06-12 20:51:56 +00:00
tails = - 1
)
2021-06-12 20:43:13 +00:00
2021-06-13 17:37:15 +00:00
# This sets Skeleton: Tails Needed to 0 and is implemented separately
2021-06-12 20:51:56 +00:00
SKIP_TAILS = Action (
" Decide your Tailless Animal needs no tail " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value
2021-06-12 20:51:56 +00:00
)
2021-06-12 20:43:13 +00:00
2021-06-11 18:43:37 +00:00
def __str__ ( self ) :
return str ( self . value )
2021-06-09 15:29:56 +00:00
2021-06-18 20:08:28 +00:00
class Adjustment ( Enum ) :
2021-06-18 19:44:30 +00:00
""" An action that is taken after all parts have been added to a skeleton. """
2021-06-13 15:39:13 +00:00
CARVE_AWAY_AGE = Action (
" Carve away some evidence of age " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value ,
2021-06-13 15:39:13 +00:00
antiquity = - 2
)
DISGUISE_AMALGAMY = Action (
" Disguise the amalgamy of this piece " ,
2021-06-15 13:30:21 +00:00
cost = Cost . ACTION . value + 25 * Cost . JADE_FRAGMENT . value ,
2021-06-13 15:39:13 +00:00
amalgamy = - 2
)
MAKE_LESS_DREADFUL = Action (
" Make your skeleton less dreadful " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value ,
2021-06-13 15:39:13 +00:00
menace = - 2
)
def __str__ ( self ) :
return str ( self . value )
2021-06-18 20:08:28 +00:00
class Declaration ( Enum ) :
2021-06-18 19:44:30 +00:00
""" An action that is taken after all adjustments have been made to a skeleton. """
2021-06-13 15:52:02 +00:00
AMPHIBIAN = Action (
" Declare your (Skeleton Type) a completed Amphibian " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value
2021-06-13 15:52:02 +00:00
)
APE = Action (
" Declare your (Skeleton Type) a completed Ape " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value
2021-06-13 15:52:02 +00:00
)
BIRD = Action (
" Declare your (Skeleton Type) a completed Bird " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value
2021-06-13 15:52:02 +00:00
)
CHIMERA = Action (
" Declare your (Skeleton Type) a completed Chimera " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value ,
2021-06-13 15:52:02 +00:00
implausibility = 3
)
CURATOR = Action (
" Declare your (Skeleton Type) a completed Curator " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value
2021-06-13 15:52:02 +00:00
)
FISH = Action (
" Declare your (Skeleton Type) a completed Fish " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value
2021-06-13 15:52:02 +00:00
)
HUMANOID = Action (
" Declare your (Skeleton Type) a completed Humanoid " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value
2021-06-13 15:52:02 +00:00
)
INSECT = Action (
" Declare your (Skeleton Type) a completed Insect " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value
2021-06-13 15:52:02 +00:00
)
MONKEY = Action (
" Declare your (Skeleton Type) a completed Monkey " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value
2021-06-13 15:52:02 +00:00
)
REPTILE = Action (
" Declare your (Skeleton Type) a completed Reptile " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value
2021-06-13 15:52:02 +00:00
)
SPIDER = Action (
" Declare your (Skeleton Type) a completed Spider " ,
2021-06-13 17:43:52 +00:00
cost = Cost . ACTION . value
2021-06-13 15:52:02 +00:00
)
2021-06-08 22:28:15 +00:00
def __str__ ( self ) :
return str ( self . value )
2021-06-13 19:27:53 +00:00
2021-06-18 20:08:28 +00:00
class Embellishment ( Enum ) :
2021-06-18 19:44:30 +00:00
""" An action is taken after a declaration has been made for a skeleton. """
2021-06-13 19:27:53 +00:00
MORE_PLAUSIBLE = Action (
" Make it seem just a bit more plausible " ,
cost = Cost . ACTION . value + Cost . REVISIONIST_NARRATIVE . value ,
implausibility = - 1
)
CONVINCING_HISTORY = Action (
" Invest great time and skill in coming up with a convincing history " ,
cost = Cost . ACTION . value + 3 * Cost . REVISIONIST_NARRATIVE . value ,
implausibility = - 5
)
def __str__ ( self ) :
return str ( self . value )
2021-06-18 20:08:28 +00:00
class Buyer ( Enum ) :
2021-06-18 19:44:30 +00:00
""" An action that converts a skeleton into revenue. """
2021-06-13 19:58:51 +00:00
A_PALAEONTOLOGIST_WITH_HOARDING_PROPENSITIES = Action (
" Sell a complete skeleton to the Bone Hoarder " ,
cost = Cost . ACTION . value
)
A_NAIVE_COLLECTOR = Action (
" Sell your Skeleton to a Naive Collector " ,
cost = Cost . ACTION . value
)
A_FAMILIAR_BOHEMIAN_SCULPTRESS = Action (
" Sell your Skeleton to the Sculptress " ,
cost = Cost . ACTION . value
)
A_PEDAGOGICALLY_INCLINED_GRANDMOTHER = Action (
" Sell your skeleton to a Pedagogically Inclined Grandmother " ,
cost = Cost . ACTION . value
)
A_THEOLOGIAN_OF_THE_OLD_SCHOOL = Action (
" Sell your Skeleton to the Theologian of the Old School " ,
cost = Cost . ACTION . value
)
AN_ENTHUSIAST_OF_THE_ANCIENT_WORLD = Action (
" Sell your skeleton to an Enthusiast of the Ancient World " ,
cost = Cost . ACTION . value
)
MRS_PLENTY = Action (
" Sell a complete skeleton to Mrs Plenty " ,
cost = Cost . ACTION . value
)
A_TENTACLED_SERVANT = Action (
" Sell him your amalgamous skeleton " ,
cost = Cost . ACTION . value
)
AN_INVESTMENT_MINDED_AMBASSADOR = Action (
" Sell your skeleton to the Ambassador " ,
cost = Cost . ACTION . value
)
A_TELLER_OF_TERRORS = Action (
" Sell your skeleton to the Teller of Terrors " ,
cost = Cost . ACTION . value
)
A_TENTACLED_ENTREPRENEUR = Action (
" Sell to the Tentacled Entrepreneur " ,
cost = Cost . ACTION . value
)
AN_AUTHOR_OF_GOTHIC_TALES = Action (
" Sell to an Author of Gothic Tales " ,
cost = Cost . ACTION . value
)
A_ZAILOR_WITH_PARTICULAR_INTERESTS = Action (
" Sell your skeleton to a Zailor " ,
cost = Cost . ACTION . value
)
A_RUBBERY_COLLECTOR = Action (
" Sell to an Enthusiast of a Rubbery Menace " ,
cost = Cost . ACTION . value
)
A_CONSTABLE = Action (
" Sell to a Constable " ,
cost = Cost . ACTION . value
)
AN_ENTHUSIAST_IN_SKULLS = Action (
" Sell to the Cranial Enthusiast " ,
cost = Cost . ACTION . value
)
A_DREARY_MIDNIGHTER = Action (
" Sell to the Dreary Midnighter " ,
cost = Cost . ACTION . value
)
2021-06-15 11:56:05 +00:00
A_COLOURFUL_PHANTASIST_BAZAARINE = Action (
" Sell an amalgamous skeleton as a work of Bazaarine art " ,
cost = Cost . ACTION . value
)
2021-06-15 12:02:49 +00:00
A_COLOURFUL_PHANTASIST_NOCTURNAL = Action (
" Sell a menacing skeleton as a work of Nocturnal art " ,
cost = Cost . ACTION . value
)
2021-06-15 12:10:20 +00:00
A_COLOURFUL_PHANTASIST_CELESTIAL = Action (
" Sell an antique skeleton as a work of Celestial art " ,
cost = Cost . ACTION . value
)
2021-06-22 13:25:12 +00:00
AN_INGENUOUS_MALACOLOGIST = Action (
" Sell him a tentacle-laden skeleton " ,
cost = Cost . ACTION . value
)
2021-07-06 19:18:07 +00:00
AN_ENTERPRISING_BOOT_SALESMAN = Action (
" Sell to the Enterprising Boot Salesman " ,
cost = Cost . ACTION . value
)
2021-06-13 19:58:51 +00:00
THE_DUMBWAITER_OF_BALMORAL = Action (
" Export the Skeleton of a Neathy Bird " ,
cost = Cost . ACTION . value
)
2021-06-14 03:00:34 +00:00
THE_CARPENTERS_GRANDDAUGHTER = Action (
" Impress her with your own constructions " ,
cost = Cost . ACTION . value
)
2021-07-06 16:25:15 +00:00
THE_TRIFLING_DIPLOMAT_ANTIQUITY = Action (
2021-06-25 23:37:41 +00:00
" Sell the Diplomat an antique skeleton " ,
cost = Cost . ACTION . value
)
2021-07-06 17:33:03 +00:00
THE_TRIFLING_DIPLOMAT_BIRD = Action (
" Sell the Diplomat a fossil bird " ,
cost = Cost . ACTION . value
)
2021-07-06 16:25:15 +00:00
THE_TRIFLING_DIPLOMAT_FISH = Action (
2021-06-29 20:56:42 +00:00
" Sell the Diplomat a fossil fish " ,
cost = Cost . ACTION . value
)
2021-06-13 19:58:51 +00:00
def __str__ ( self ) :
return str ( self . value )
2021-06-18 20:08:28 +00:00
class Fluctuation ( Enum ) :
2021-06-18 19:44:30 +00:00
""" Which skeleton attribute is currently boosted. """
2021-06-08 22:28:15 +00:00
ANTIQUITY = 1
AMALGAMY = 2
2021-07-06 18:19:29 +00:00
MENACE = 3
2021-06-08 22:28:15 +00:00
2021-06-18 20:08:28 +00:00
class OccasionalBuyer ( Enum ) :
2021-06-18 19:44:30 +00:00
""" Which of several unusual buyers are available. """
2021-06-16 20:30:48 +00:00
AN_ENTHUSIAST_IN_SKULLS = [ Buyer . AN_ENTHUSIAST_IN_SKULLS ]
2021-06-13 16:01:17 +00:00
2021-06-16 20:30:48 +00:00
A_DREARY_MIDNIGHTER = [ Buyer . A_DREARY_MIDNIGHTER ]
A_COLOURFUL_PHANTASIST = [
Buyer . A_COLOURFUL_PHANTASIST_BAZAARINE ,
Buyer . A_COLOURFUL_PHANTASIST_NOCTURNAL ,
Buyer . A_COLOURFUL_PHANTASIST_CELESTIAL ,
]
2021-06-22 13:25:12 +00:00
AN_INGENUOUS_MALACOLOGIST = [ Buyer . AN_INGENUOUS_MALACOLOGIST ]
2021-07-06 19:18:07 +00:00
AN_ENTERPRISING_BOOT_SALESMAN = [ Buyer . AN_ENTERPRISING_BOOT_SALESMAN ]
2021-06-16 20:30:48 +00:00
2021-07-06 17:18:49 +00:00
DiplomatFascination = Enum (
' DiplomatFascination ' ,
( ( diplomat . name [ 22 : ] , diplomat ) for diplomat in Buyer
if diplomat . name . startswith ( ' THE_TRIFLING_DIPLOMAT_ ' ) ) ,
module = __name__
)
DiplomatFascination . __doc__ = " The current fascination of the Trifling Diplomat. "
2021-06-29 20:56:42 +00:00
2021-06-25 23:37:41 +00:00
def Solve ( shadowy_level , bone_market_fluctuations , zoological_mania , 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-06-24 13:45:59 +00:00
multiplier = 115 if zoological_mania in [ Declaration . FISH , Declaration . INSECT , Declaration . SPIDER ] else 110
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 ( ) )
2021-06-08 22:28:15 +00:00
value = model . NewIntVar ( 0 , cp_model . INT32_MAX , ' value ' )
2021-06-24 13:45:59 +00:00
model . AddDivisionEquality ( value , multiplied_value , 100 )
2021-06-08 22:28:15 +00:00
2021-06-24 13:45:59 +00:00
del original_value , multiplier , multiplied_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 ] )
model . Add ( torso_style > = 10 ) . OnlyEnforceIf ( actions [ Declaration . HUMANOID ] )
model . Add ( torso_style < = 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 ] )
model . Add ( torso_style > = 10 ) . OnlyEnforceIf ( actions [ Declaration . APE ] )
model . Add ( torso_style < = 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 ] )
model . Add ( torso_style > = 10 ) . OnlyEnforceIf ( actions [ Declaration . MONKEY ] )
model . Add ( torso_style < = 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 ( ) )
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
# TODO: Add actual difficulty level
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 ] )
# TODO: Add actual difficulty level
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
# TODO: Add actual difficulty level
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-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 )
2021-06-08 22:28:15 +00:00
2021-06-14 00:40:11 +00:00
class EnumAction ( argparse . Action ) :
def __init__ ( self , * * kwargs ) :
# Pop off the type value
2021-06-16 22:28:16 +00:00
enum = kwargs . pop ( ' type ' , None )
nargs = kwargs . pop ( ' nargs ' , None )
2021-06-14 00:40:11 +00:00
# Generate choices from the Enum
2021-06-16 22:28:16 +00:00
kwargs . setdefault ( ' choices ' , tuple ( member . name . lower ( ) for member in enum ) )
2021-06-14 00:40:11 +00:00
super ( EnumAction , self ) . __init__ ( * * kwargs )
self . _enum = enum
2021-06-16 22:28:16 +00:00
self . _nargs = nargs
2021-06-14 00:40:11 +00:00
def __call__ ( self , parser , namespace , values , option_string = None ) :
# Convert value back into an Enum
enum = self . _enum [ values . upper ( ) ]
2021-06-16 22:28:16 +00:00
if self . _nargs is None or self . _nargs == ' ? ' :
setattr ( namespace , self . dest , enum )
else :
items = getattr ( namespace , self . dest , list ( ) )
items . append ( enum )
setattr ( namespace , self . dest , items )
2021-06-14 00:40:11 +00:00
def main ( ) :
2021-06-25 22:11:43 +00:00
parser = argparse . ArgumentParser (
prog = ' Bone Market Solver ' ,
description = " Devise the optimal skeleton at the Bone Market in Fallen London. " ,
argument_default = argparse . SUPPRESS ,
)
2021-06-16 20:30:48 +00:00
2021-06-19 12:32:19 +00:00
parser . add_argument (
" -s " , " --shadowy " ,
type = int ,
required = True ,
help = " the effective level of Shadowy used for selling to buyers " ,
dest = ' shadowy_level '
)
2021-06-14 00:40:11 +00:00
parser . add_argument (
2021-06-18 18:48:20 +00:00
" -f " , " --bone-market-fluctuations " ,
2021-06-14 00:40:11 +00:00
action = EnumAction ,
type = Fluctuation ,
required = True ,
2021-06-18 18:48:20 +00:00
help = " current value of Bone Market Fluctuations, which grants various bonuses to certain buyers " ,
2021-06-14 00:40:11 +00:00
dest = ' bone_market_fluctuations '
)
2021-06-16 20:30:48 +00:00
2021-06-14 00:40:11 +00:00
parser . add_argument (
2021-06-18 18:48:20 +00:00
" -m " , " --zoological-mania " ,
2021-06-14 00:40:11 +00:00
action = EnumAction ,
type = Declaration ,
required = True ,
2021-06-25 23:40:39 +00:00
help = " current value of Zoological Mania, which grants a percentage bonus to value for a certain declaration " ,
2021-06-14 00:40:11 +00:00
dest = ' zoological_mania '
)
2021-06-16 20:30:48 +00:00
2021-06-25 22:37:32 +00:00
buyer = parser . add_mutually_exclusive_group ( )
2021-06-25 23:37:41 +00:00
transient_buyers = buyer . add_argument_group ( )
transient_buyers . add_argument (
2021-06-18 18:48:20 +00:00
" -o " , " --occasional-buyer " ,
2021-06-16 20:30:48 +00:00
action = EnumAction ,
type = OccasionalBuyer ,
2021-06-18 18:48:20 +00:00
help = " current value of Occasional Buyer, which allows access to a buyer that is not otherwise available " ,
2021-06-16 20:30:48 +00:00
dest = ' occasional_buyer '
)
2021-06-25 23:37:41 +00:00
transient_buyers . add_argument (
" -d " , " --diplomat-fascination " ,
action = EnumAction ,
type = DiplomatFascination ,
help = " current value of The Diplomat ' s Current Fascination, which determines what the Trifling Diplomat is interested in " ,
dest = ' diplomat_fascination '
)
2021-06-16 20:30:48 +00:00
buyer . add_argument (
2021-06-18 18:48:20 +00:00
" -b " , " --buyer " , " --desired-buyer " ,
2021-06-14 00:40:11 +00:00
action = EnumAction ,
2021-06-16 22:28:16 +00:00
nargs = ' + ' ,
2021-06-14 00:40:11 +00:00
type = Buyer ,
2021-06-18 18:48:20 +00:00
help = " specific buyer that skeleton should be designed for (if declared repeatedly, will choose from among those provided) " ,
2021-06-16 22:28:16 +00:00
dest = ' desired_buyers '
2021-06-14 00:40:11 +00:00
)
2021-06-16 20:30:48 +00:00
2021-06-14 00:40:11 +00:00
parser . add_argument (
2021-06-18 18:48:20 +00:00
" -c " , " --cost " , " --maximum-cost " ,
2021-06-14 00:40:11 +00:00
type = int ,
2021-06-18 18:48:20 +00:00
help = " maximum number of pennies that should be invested in skeleton " ,
2021-06-14 00:40:11 +00:00
dest = ' maximum_cost '
)
2021-06-19 12:33:46 +00:00
2021-06-14 00:40:11 +00:00
parser . add_argument (
2021-06-18 18:48:20 +00:00
" -e " , " --exhaustion " , " --maximum_exhaustion " ,
2021-06-14 00:40:11 +00:00
type = int ,
2021-06-18 18:48:20 +00:00
help = " maximum exhaustion that skeleton should generate " ,
2021-06-14 00:40:11 +00:00
dest = ' maximum_exhaustion '
)
2021-06-19 12:33:46 +00:00
2021-06-14 00:40:11 +00:00
parser . add_argument (
2021-06-18 18:48:20 +00:00
" -v " , " --verbose " ,
2021-06-14 00:40:11 +00:00
nargs = ' ? ' ,
2021-06-18 18:48:20 +00:00
const = True ,
2021-06-14 00:40:11 +00:00
default = False ,
type = bool ,
2021-06-18 18:48:20 +00:00
help = " whether the solver should output search progress rather than showing intermediate solutions " ,
2021-06-14 00:40:11 +00:00
dest = ' verbose '
)
2021-06-19 12:33:46 +00:00
2021-06-16 16:32:05 +00:00
parser . add_argument (
2021-06-18 18:48:20 +00:00
" -t " , " --time-limit " ,
2021-06-16 16:32:05 +00:00
type = float ,
2021-06-18 18:48:20 +00:00
help = " maximum number of seconds that solver runs for " ,
2021-06-16 16:32:05 +00:00
dest = ' time_limit '
)
2021-06-19 12:33:46 +00:00
2021-06-18 21:18:40 +00:00
parser . add_argument (
" -w " , " --workers " ,
type = int ,
help = " number of search worker threads to run in parallel (default: one worker per available CPU thread) " ,
dest = ' workers '
)
2021-06-14 00:40:11 +00:00
args = parser . parse_args ( )
2021-06-25 22:11:43 +00:00
arguments = vars ( args )
2021-06-15 21:50:28 +00:00
2021-06-25 22:11:43 +00:00
if not arguments . pop ( ' verbose ' ) :
2021-06-15 21:50:28 +00:00
def WrappedSolve ( stdscr , arguments ) :
2021-06-19 13:02:07 +00:00
# Prevents crash if window is too small to fit text
stdscr . scrollok ( True )
2021-06-15 21:50:28 +00:00
# Move stdscr to last position
2021-06-25 22:11:43 +00:00
arguments [ ' stdscr ' ] = stdscr
return Solve ( * * arguments )
2021-06-15 21:50:28 +00:00
print ( curses . wrapper ( WrappedSolve , arguments ) )
else :
2021-06-25 22:11:43 +00:00
print ( Solve ( * * arguments ) )
2021-06-14 00:40:11 +00:00
2021-06-18 20:13:03 +00:00
if __name__ == ' __main__ ' :
main ( )