ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

公式计算,分量累加计算优化

2019-03-07 17:03:59  阅读:197  来源: 互联网

标签:__ Node name self 累加 计算 ._ def 分量


公式计算,分量累加计算优化


问题

计算公式 f = (base + genconst) * percent * genpercent + const
公式中的运算变量均为长度为 26 的一维向量。 在游戏卡牌中,假如有 20 个养成系统, 会对公式中的某个或多个部分提供一个加成,在 20 个系统加成完成后, 计算出最终的结果。

现有计算方式

在一个函数中, 创建与公式对应的变量, 依次计算 20 个养成系统的加成并将养成累加到对应的变量, 最终得到结果。
这样的计算方式,非常简单直观。 但存在两个的问题:

  1. 当只有某个养成系统变化时,为了得到结果, 你需要完整的把 20 个都跑一遍
  2. 当其中某个养成计算结果比较费时时,你需要对特定的养成做缓存来提高计算的效率

优化计算方式

将公式拆解成一颗树的形式,如下所示:
属性优化示意图

每个养成系统将自己的值放到对应的节点, 当某个养成系统有改动时,去设置对应节点的值,然后改动以增量的形式沿着路径往上走,直到根节点,这样根节点的值就是最新的,同时也不会引起到其他节点的计算。

这样就很好的处理了现有计算方式的两个问题, 引入了额外的内存消耗, 但在可接受范围,在python 中不要忘记用 slots 优化内存。

demo 代码:

#!/usr/bin/python
# -*- coding: utf-8 -*-

try:
    from game.object import AttrDefs
# for test
except ImportError:
    AttrMaxID = 26 + 1
else:
    AttrMaxID = AttrDefs.attrTotal + 1

import numpy as np


def dict2attrs(d):
    value = np.zeros(AttrMaxID)
    for i, attr in enumerate(AttrDefs.attrsEnum):
        if attr:
            value[i] = d.get(attr, 0)
    return np.array(value)

def attrs2dict(attr):
    d = {}
    for i, v in enumerate(attr):
        if v:
            d[AttrDefs.attrsEnum[i]] = v
    return d

class AttrContext(object):
    '''simple context'''
    def __init__(self, game, scene=0, **kwargs):
        self.game = game
        self.scene = scene
        self.__dict__.update(kwargs)

    # TODO: use statement with to achieve a temp context


class Node(object):
    __slots__ = ("name", "ret", "_adds", "_parent", "left", "right", "tag")

    def __init__(self, name, tag=None, parent=None, left=None, right=None):
        self.name = name
        self.ret = np.zeros(AttrMaxID)
        self._adds = {}
        self._parent = parent
        self.left = left
        self.right = right
        self.tag = tag

    def __str__(self):
        return '<Node object at 0x%x>\n%s: %s\n' % (id(self), self.name, tuple(self.ret))

    def addLeft(self, node):
        self.left = node
        node._parent = self
        node.tag = 'l'

    def addRight(self, node):
        self.right = node
        node._parent = self
        node.tag = 'r'

    def set(self, k, v):
        d = v - self._adds.get(k, 0)
        if any(d):
            self._adds[k] = v
            self.ret += d
            self.onChange(d)

    def onChange(self, d):
        if self._parent:
            self._parent.change(d, self.tag)

    def change(self, d, tag):
        if tag == 'l':
            v = self.right.ret
        else:
            v = self.left.ret

        if self.name == '*':
            d1 = v*d
        elif self.name == '+':
            d1 = d

        if any(d1):
            self.ret += d1
            self.onChange(d1)

class Calculator(object):

    def __init__(self, ctx):
        self.ctx = ctx
        self._nodes = {}
        self._ft = self.buildFTree()
        self.init()

    # set default value
    def init(self):
        self.percent.set('default', np.ones(AttrMaxID))
        self.genpercent.set('default', np.ones(AttrMaxID))

    def __getattr__(self, name):
        try:
            return self._nodes[name]
        except KeyError:
            raise AttributeError("%s instance has no attribute '%s'" % (self.__class__.__name__, name))

    def buildFTree(self, f):
        root = None
        p = Node('+')
        root = p

        base = Node('base')
        genconst = Node('genconst')
        percent = Node('percent')
        genpercent = Node('genpercent')
        const = Node('const')

        self._nodes['base'] = base
        self._nodes['genconst'] = genconst
        self._nodes['percent'] = percent
        self._nodes['genpercent'] = genpercent
        self._nodes['const'] = const

        p.addRight(const)
        tn = Node('*')
        p.addLeft(tn)
        p = tn

        p.addRight(genpercent)
        tn = Node('*')
        p.addLeft(tn)
        p = tn

        p.addRight(percent)
        tn = Node('+')
        p.addLeft(tn)
        p = tn

        p.addLeft(base)
        p.addRight(genconst)

        return root

    @property
    def result(self):
        return attrs2dict(self._ft.ret)

    # show formula
    def showf(self):
        f = []

        def show(p, f):
            if p.name in '+*':
                f.append('(')

            if p.left:
                show(p.left, f)
            f.append(p.name)
            if p.right:
                show(p.right, f)

            if p.name in '+*':
                f.append(')')

        show(self._ft, f)
        print(''.join(f))

标签:__,Node,name,self,累加,计算,._,def,分量
来源: https://www.cnblogs.com/nowg/p/10490707.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有