diff --git a/README.md b/README.md index fca9820..11adac5 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,15 @@ For best results, it is recommended to specify every world quality you can. Depe You do *not* need to specify buyers to use this solver. The solver will try to maximize profit margin for all available buyers if you do not specify any, which may be very useful if you have no particular objective in mind. Specifying multiple buyers will cause the solver to choose from among them. +### Blacklisting + +If you wish to prohibit certain options, you may do so by passing their exact identifiers (e.g. "Skull.VICTIM\_SKULL") to the blacklist. + +You may wish to blacklist options that: +* require a Profession, Ambition, or story you do not have +* add Exhaustion +* you simply don't have a good source for + ## Caveats The solver aims to maximize profit margin, rather than sheer profit. This is because it may be more profitable to make many smaller skeletons than one massive skeleton. diff --git a/bonemarketsolver/__main__.py b/bonemarketsolver/__main__.py index 8b0d085..d00f5d8 100644 --- a/bonemarketsolver/__main__.py +++ b/bonemarketsolver/__main__.py @@ -1,6 +1,7 @@ import argparse import curses +from .objects.blacklistaction import BlacklistAction from .objects.enumaction import EnumAction from .solve import * @@ -85,6 +86,15 @@ skeleton_parameters.add_argument( dest='maximum_exhaustion' ) +skeleton_parameters.add_argument( + "--blacklist", + action=BlacklistAction, + nargs='+', + help="components, options, or buyers that should not be used by the solver", + metavar="Enum.MEMBER", + dest='blacklist' + ) + solver_options = parser.add_argument_group( "solver options", diff --git a/bonemarketsolver/data/skulls.py b/bonemarketsolver/data/skulls.py index f17e35f..d01a763 100644 --- a/bonemarketsolver/data/skulls.py +++ b/bonemarketsolver/data/skulls.py @@ -47,14 +47,14 @@ class Skull(Enum): ) # Adds Exhaustion - # ENGRAVED_SKULL = Action( - # "Affix a Custom-Engraved Skull to your (Skeleton Type)", - # cost = Cost.ACTION.value + Cost.ENGRAVED_SKULL.value, - # value = 10000, - # skulls_needed = -1, - # skulls = 1, - # exhaustion = 2 - # ) + ENGRAVED_SKULL = Action( + "Affix a Custom-Engraved Skull to your (Skeleton Type)", + cost = Cost.ACTION.value + Cost.ENGRAVED_SKULL.value, + value = 10000, + skulls_needed = -1, + skulls = 1, + exhaustion = 2 + ) EYELESS_SKULL = Action( "Affix an Eyeless Skull to your (Skeleton Type)", @@ -76,13 +76,13 @@ class Skull(Enum): ) # Seeking the Name of Mr. Eaten - # OWN_SKULL = Action( - # "Duplicate your own skull and affix it here", - # cost = Cost.ACTION.value + 1000*Cost.BONE_FRAGMENT.value, - # value = -250, - # skulls_needed = -1, - # skulls = 1 - # ) + OWN_SKULL = Action( + "Duplicate your own skull and affix it here", + cost = Cost.ACTION.value + 1000*Cost.BONE_FRAGMENT.value, + value = -250, + skulls_needed = -1, + skulls = 1 + ) PENTAGRAMMIC_SKULL = Action( "Affix a Pentagrammic Skull to your (Skeleton Type)", @@ -139,13 +139,13 @@ class Skull(Enum): ) # Licentiate - # VICTIM_SKULL = Action( - # "Cap this with a victim’s skull", - # cost = Cost.ACTION.value, - # value = 250, - # skulls_needed = -1, - # skulls = 1 - # ) + VICTIM_SKULL = Action( + "Cap this with a victim’s skull", + cost = Cost.ACTION.value, + value = 250, + skulls_needed = -1, + skulls = 1 + ) def __str__(self): return str(self.value) diff --git a/bonemarketsolver/data/torsos.py b/bonemarketsolver/data/torsos.py index c63bb14..29fccb9 100644 --- a/bonemarketsolver/data/torsos.py +++ b/bonemarketsolver/data/torsos.py @@ -20,15 +20,15 @@ class Torso(Enum): ) # Licentiate - # VICTIM_SKELETON = Action( - # "Supply a skeleton of your own", - # cost = Cost.ACTION.value, - # torso_style = 10, - # value = 250, - # skulls_needed = 1, - # arms = 2, - # legs = 2 - # ) + VICTIM_SKELETON = Action( + "Supply a skeleton of your own", + cost = Cost.ACTION.value, + torso_style = 10, + value = 250, + skulls_needed = 1, + arms = 2, + legs = 2 + ) HUMAN_RIBCAGE = Action( "Build on the Human Ribcage", diff --git a/bonemarketsolver/objects/blacklistaction.py b/bonemarketsolver/objects/blacklistaction.py new file mode 100644 index 0000000..1a714b2 --- /dev/null +++ b/bonemarketsolver/objects/blacklistaction.py @@ -0,0 +1,39 @@ +__all__ = ['BlacklistAction'] +__author__ = "Jeremy Saklad" + +from argparse import Action + +from ..data.adjustments import Adjustment +from ..data.appendages import Appendage +from ..data.buyers import Buyer +from ..data.declarations import Declaration +from ..data.embellishments import Embellishment +from ..data.skulls import Skull +from ..data.torsos import Torso + +def convert_to_enum(value): + split = value.split(".", 1) + + enum = globals()[split[0]] + return enum[split[1]] + +class BlacklistAction(Action): + def __init__(self, **kwargs): + nargs = kwargs.get('nargs') + + super(BlacklistAction, self).__init__(**kwargs) + + self._nargs = nargs + + def __call__(self, parser, namespace, values, option_string=None): + if self._nargs is None or self._nargs == '?': + # Convert value back into an Enum + enum = convert_to_enum(value) + + setattr(namespace, self.dest, enum) + else: + # Convert values back into Enums + enums = [convert_to_enum(value) for value in values] + + items = getattr(namespace, self.dest, list()) + enums + setattr(namespace, self.dest, items)