Source code for turberfield.eargain.exchange

#!/usr/bin/env python3
# encoding: UTF-8

# This file is part of turberfield.
#
# Turberfield is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Turberfield is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with turberfield.  If not, see <http://www.gnu.org/licenses/>.

import asyncio
from collections import defaultdict
from datetime import timedelta
import itertools
import logging

from turberfield.common.accounts import Accounts
from turberfield.common.accounts import GoodsOnCredit
from turberfield.common.dramatics import Dramatics
from turberfield.common.inventory import Inventory
from turberfield.common.inventory import Location
from turberfield.common.inventory import Resource
from turberfield.common.types import Move
from turberfield.common.types import RenderGoods

from turberfield.dynamics.types import Stop

from turberfield.eargain.types import Commodity
from turberfield.eargain.types import CreditRelationship
from turberfield.eargain.types import HOUR
from turberfield.eargain.types import WEEK
from turberfield.eargain.types import Mass
from turberfield.eargain.types import TradePosition


__doc__ = """
Here's how you would create regular goods-on-credit exchange between
characters in a simulation.

.. code-block:: python

    loop = asyncio.get_event_loop()

    # Bits and pieces from turberfield.common
    dramatics = Dramatics()
    jq = JobQueue(loop=loop)

    # The characters have to meet in the same place
    tavern = Location("quarry", "furlong", "tavern", None)

    # The characters' need to buy or sell is stored as a Drama
    dramatics.relations[merchant, Commodity.STON].add(TradePosition.buying)
    dramatics.relations[miner, Commodity.FOOD].add(TradePosition.buying)
    dramatics.relations[merchant, Commodity.FOOD].add(TradePosition.selling)
    dramatics.relations[miner, Commodity.STON].add(TradePosition.selling)

    routine = Exchange(merchant, miner, meet=tavern)

    tasks = [Simulation.task(loop, routine, jq)]
    sim = Simulation(tasks, jq, buf)

"""


[docs]class Exchange: def __init__( self, *args, start:int=None, end:int=None, period:int=None, meet:Location=None ): self.parties = args self.start = start or timedelta(days=2, hours=8).total_seconds() self.end = end or timedelta( seconds=self.start, hours=4).total_seconds() self.period = period or WEEK self.meet = meet assert self.meet @asyncio.coroutine def __call__(self, q, jq, priority): log = logging.getLogger( "turberfield.eargain.exchange.{}".format(priority)) accounts = Accounts() dramatics = Dramatics() inventory = Inventory() tick = None while not isinstance(tick, Stop): tick = yield from q.get() if not self.start <= tick.t % self.period < self.end: continue parties = list(self.parties) for p in self.parties: if p not in inventory.places[self.meet]: parties.remove(p) yield from jq.put( tick.t + HOUR, tick.priority, Move(p, self.meet)) market = defaultdict(lambda: defaultdict(set)) shouts = ( (a, c, t) for a, c in itertools.product(parties, Commodity) for t in dramatics.relations[a, c] if isinstance(t, TradePosition) ) for a, c, p in shouts: market[c][p].add(a) log.debug(market) for commodity, positions in market.items(): try: src = positions[TradePosition.selling].pop() dst = positions[TradePosition.buying].pop() except KeyError as e: log.debug(e) continue else: measure = Mass.Kg # FIXME quantity = ( inventory.pockets[src][commodity] / measure.value) if quantity < 1: log.debug(quantity) continue goods = Resource(commodity, measure, quantity) yield from jq.put( tick.t, tick.priority, RenderGoods( src, dst, goods, self.meet, CreditRelationship.established) ) else: return tick