Skip to content

Instantly share code, notes, and snippets.

@dwightguth
Created May 31, 2020 19:33
Show Gist options
  • Save dwightguth/e79e21309efd53b3281404f4cfe12220 to your computer and use it in GitHub Desktop.
Save dwightguth/e79e21309efd53b3281404f4cfe12220 to your computer and use it in GitHub Desktop.
from z3 import *
npcs = []
biomes = []
class npc(object):
def __init__(self, name):
self.name = name
self.sells = True
self._loves = []
self._likes = []
self._dislikes = []
self._hates = []
self.near = {}
npcs.append(self)
def loves(self, *loves):
self._loves = loves
def likes(self, *likes):
self._likes = likes
def dislikes(self, *dislikes):
self._dislikes = dislikes
def hates(self, *hates):
self._hates = hates
guide = npc("Guide")
merchant = npc("Merchant")
zoologist = npc("Zoologist")
golfer = npc("Golfer")
nurse = npc("Nurse")
tavernkeep = npc("Tavernkeep")
party_girl = npc("Party girl")
wizard = npc("Wizard")
demolitionist = npc("Demolitionist")
goblin_tinkerer = npc("Goblin tinkerer")
clothier = npc("Clothier")
dye_trader = npc("Dye trader")
arms_dealer = npc("Arms dealer")
steampunker = npc("Steampunker")
dryad = npc("Dryad")
painter = npc("Painter")
witch_doctor = npc("Witch doctor")
stylist = npc("Stylist")
angler = npc("Angler")
pirate = npc("Pirate")
mechanic = npc("Mechanic")
tax_collector = npc("Tax collector")
cyborg = npc("Cyborg")
#santa = npc("Santa claus")
truffle = npc("Truffle")
class biome(object):
def __init__(self, name):
self.name = name
biomes.append(self)
forest = biome("Forest")
hallow = biome("Hallow")
underground = biome("Underground")
desert = biome("Desert")
jungle = biome("Jungle")
ocean = biome("Ocean")
snow = biome("Snow")
mushroom = biome("Mushroom")
guide.likes(forest, clothier, zoologist)
guide.dislikes(ocean, steampunker)
guide.hates(painter)
guide.sells = False
merchant.likes(forest, golfer, nurse)
merchant.dislikes(desert, tax_collector)
merchant.hates(angler)
zoologist.loves(witch_doctor)
zoologist.likes(forest, golfer)
zoologist.dislikes(desert, angler)
zoologist.hates(arms_dealer)
golfer.loves(angler)
golfer.likes(forest, painter, zoologist)
golfer.dislikes(underground, pirate)
golfer.hates(merchant)
nurse.loves(arms_dealer)
nurse.likes(hallow, wizard)
nurse.dislikes(snow, dryad, party_girl)
nurse.hates(zoologist)
tavernkeep.loves(demolitionist)
tavernkeep.likes(hallow, goblin_tinkerer)
tavernkeep.dislikes(snow, guide)
tavernkeep.hates(dye_trader)
party_girl.loves(wizard, zoologist)
party_girl.likes(hallow, stylist)
party_girl.dislikes(underground, merchant)
party_girl.hates(tax_collector)
wizard.loves(golfer)
wizard.likes(hallow, merchant)
wizard.dislikes(ocean, witch_doctor)
wizard.hates(cyborg)
demolitionist.loves(tavernkeep)
demolitionist.likes(underground, mechanic)
demolitionist.dislikes(ocean, arms_dealer, goblin_tinkerer)
goblin_tinkerer.loves(mechanic)
goblin_tinkerer.likes(underground, dye_trader)
goblin_tinkerer.dislikes(jungle, clothier)
goblin_tinkerer.hates(stylist)
clothier.loves(truffle)
clothier.likes(underground, tax_collector)
clothier.dislikes(hallow, nurse)
clothier.hates(mechanic)
dye_trader.likes(desert, arms_dealer, painter)
dye_trader.dislikes(forest, steampunker)
dye_trader.hates(pirate)
arms_dealer.loves(nurse)
arms_dealer.likes(desert, steampunker)
arms_dealer.dislikes(snow, golfer)
arms_dealer.hates(demolitionist)
steampunker.loves(cyborg)
steampunker.likes(desert, painter)
steampunker.dislikes(jungle, dryad, wizard, party_girl)
dryad.likes(jungle, witch_doctor, truffle)
dryad.dislikes(desert, angler)
dryad.hates(golfer)
painter.loves(dryad)
painter.likes(jungle, party_girl)
painter.dislikes(forest, truffle, cyborg)
witch_doctor.likes(jungle, dryad, guide)
witch_doctor.dislikes(hallow, nurse)
witch_doctor.hates(truffle)
stylist.loves(dye_trader)
stylist.likes(ocean, pirate)
stylist.dislikes(snow, tavernkeep)
stylist.hates(goblin_tinkerer)
angler.likes(ocean, demolitionist, party_girl, tax_collector)
angler.hates(tavernkeep)
angler.sells = False
pirate.loves(angler)
pirate.likes(ocean, tavernkeep)
pirate.dislikes(underground, stylist)
pirate.hates(guide)
mechanic.loves(goblin_tinkerer)
mechanic.likes(snow, cyborg)
mechanic.dislikes(underground, arms_dealer)
mechanic.hates(clothier)
tax_collector.loves(merchant)
tax_collector.likes(snow, party_girl)
tax_collector.dislikes(hallow, demolitionist, mechanic)
#tax_collector.hates(santa)
tax_collector.sells = False
cyborg.likes(snow, steampunker, pirate, stylist)
cyborg.dislikes(jungle, zoologist)
cyborg.hates(wizard)
#santa.loves(snow)
#santa.hates(desert, tax_collector)
truffle.loves(guide)
truffle.likes(dryad)
truffle.dislikes(clothier)
truffle.hates(witch_doctor)
NPC = Datatype("NPC")
for n in npcs:
NPC.declare(n.name)
NPC = NPC.create()
for n in npcs:
n.ctr = getattr(NPC, n.name)
Biome = Datatype("Biome")
for b in biomes:
Biome.declare(b.name)
Biome = Biome.create()
for b in biomes:
b.ctr = getattr(Biome, b.name)
for n in npcs:
n.biome = Const(n.name + "_biome", Biome)
n.near = {}
for i in range(len(npcs)):
for j in range(i+1, len(npcs)):
near = Bool("near_" + npcs[i].name + "_" + npcs[j].name)
npcs[i].near[npcs[j].name] = near
npcs[j].near[npcs[i].name] = near
r = RealVal
def modifier(l, n, mod, result):
if isinstance(l, biome):
return result + If(l.ctr == n.biome, mod, 0)
elif isinstance(l, npc):
return result + If(n.near[l.name], mod, 0)
else:
raise
def happiness(npc):
result = 90
for l in npc._loves:
result = modifier(l, npc, -10, result)
for l in npc._likes:
result = modifier(l, npc, -5, result)
for l in npc._dislikes:
result = modifier(l, npc, 5, result)
for l in npc._hates:
result = modifier(l, npc, 10, result)
return If(result < 78, 0,
If(result < 83, 1,
If(result < 88, 2,
If(result < 93, 3,
If(result < 98, 4,
If(result < 103, 5,
If(result < 108, 6,
If(result < 113, 7,
If(result < 118, 8,
If(result < 123, 9,
If(result < 128, 10,
If(result < 133, 11,
If(result < 138, 12,
If(result < 143, 13,
If(result < 148, 14,
15)))))))))))))))
total = 0
for n in npcs:
if n.sells:
n.happiness = happiness(n)
total += n.happiness
o = Optimize()
o.add(truffle.biome == mushroom.ctr)
o.add(goblin_tinkerer.happiness == 0)
for n in npcs:
nnear = 0
for n2 in npcs:
if n.name != n2.name:
o.add(Implies(n.near[n2.name], n.biome == n2.biome))
nnear += If(n.near[n2.name], 1, 0)
o.add(nnear < 2)
o.minimize(total)
print(o.check())
m = o.model()
print(m.eval(total))
for n in npcs:
print n.name, ":", m[n.biome], "=", str(m.eval(happiness(n)).as_long() * 5 + 75) + "%",
near=False
for n2 in npcs:
if n.name != n2.name:
if m[n.near[n2.name]]:
near=True
if near:
print "near",
for n2 in npcs:
if n.name != n2.name:
if m[n.near[n2.name]]:
print(n2.name),
print
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment