【问题标题】:Prioritizing elements from a dictionary对字典中的元素进行优先排序
【发布时间】:2018-04-22 13:53:54
【问题描述】:

我必须用 pyton 以非常简单的方式制作类似星际争霸的游戏。

我要做的一个任务是创建一个小的耕作算法,以便让船只计算它们与小行星之间的距离,选择离它最近的一个沙子。

所有游戏数据都包含在字典中,这里是一个示例:

database = {
    'player1': {
        'type': 'player',
        'ships': {
            'shipOne': {
                'life': 3,
                'type': 'excavator-M',
                'taille': 5,
                'tonnage': 4,
                'remaining_tonnage': 4,
                'status': 'unlock',
                'portée': 0,
                'position': [20, 3],
                'attack': 0,
                'cost': 2
            },
            'shipTwo': {
                'life': 3,
                'type': 'excavator-M',
                'taille': 5,
                'tonnage': 4,
                'remaining_tonnage': 4,
                'status': 'unlock',
                'portée': 0,
                'position': [20, 3],
                'attack': 0,
                'cost': 2
            }
        },
        'actions': {
            'purchases': {},
            'moves': {},
            'mining': {},
            'attacks': {},
            '(un)lock': {}},
            'ores': 995},
            'parameters': {
                'turn_count': 19,
                'columns': 41,
                'lines': 40},
                'asteroids': {
                    '10 14': {
                        'capacity': 12,
                        'pos': [10, 14],
                        'farm_rate': 1
                    },
                    '5 21': {
                        'capacity': 12,
                        'pos': [5, 21],
                        'farm_rate': 2
                    },
                    '20 6': {
                        'capacity': 12,
                        'pos': [20, 6],
                        'farm_rate': 2
                    }
                }
            }

我试着像这样继续:

1° 创建字典['asteroids] 的副本,这样我就可以几乎减少小行星中包含的矿石量,而不会发送到同一小行星上的许多船只。

2° 使用循环创建一个字典“ships_dest”,我在其中添加每艘船的名称作为键,与该键关联的未来元素是最近的非空小行星的目的地。

3° 对于每艘船,我计算它与所有小行星的距离。并将此值添加到与键“距离”关联的字典 samp_asteroids 中。

4° 我创建了一个名为“priority_list”的列表,其中包含每个小行星的名称,它将用于成对比较距离并删除最远的小行星。

我们的想法是选择最近的具有最高农场率的小行星,并将其与字典 ship_dest 中的正确船相关联。

这是我尝试过的:

ships_dest = dict()
samp_asteroids = copy.deepcopy(database['asteroids'])

priority_list = list()

for ship in database['player1']['ships']:
    ships_dest.update({ship:''})

    for asteroid in samp_asteroids:
        priority_list.append(asteroid)
        distance = abs(database['player1']['ships'][ship]['position'][0] - database['asteroids'][asteroid]['pos'][0]) + abs(database['player1']['ships'][ship]['position'][1] - database['asteroids'][asteroid]['pos'][1])
        samp_asteroids[asteroid].update({'distance':distance})

for ship in database['player1']['ships']:  

    for asteroid in samp_asteroids:

            if database['asteroids'][asteroid]['capacity'] != 0:

                if samp_asteroids[asteroid]['capacity'] != 0:

                    ships_dest.update({ship:database['asteroids'][best_ast(samp_asteroids,priority_list)]['pos']})

                    samp_asteroids[best_ast(samp_asteroids,priority_list)]['capacity'] -= database['player1']['ships'][ship]['tonnage']

这是我用来选择最近的具有最佳耕作率的小行星的功能:

def best_ast(samp_asteroids,priority_list): 
    """
    Browse a list containing each asteroids name and return the closest asteroid to the considered ship.

    Parameters
    ----------

    - samp_asteroids : dictionary containing the data about the asteroids on the board. (dict)

    - priority_list : list containing the name of each asteroid. (list)

    Return
    ------

    - The name of the closest asteroid with the best farming rate. (str)

    """

    if len(priority_list) == 1:
        return priority_list[0]

    else:
        if samp_asteroids[priority_list[0]]['distance'] > samp_asteroids[priority_list[1]]['distance']: # on garde la plus petite distance
            priority_list.remove(priority_list[0])

        elif samp_asteroids[priority_list[0]]['distance'] < samp_asteroids[priority_list[1]]['distance']: # on garde la plus petite distance
            priority_list.remove(priority_list[1])

        else:
            if samp_asteroids[priority_list[0]]['farm_rate'] < samp_asteroids[priority_list[1]]['farm_rate']:
                priority_list.remove(priority_list[0])

            elif samp_asteroids[priority_list[1]]['farm_rate'] < samp_asteroids[priority_list[0]]['farm_rate']:
                priority_list.remove(priority_list[1])

        return(best_ast(samp_asteroids,priority_list)) 

有没有人想在不使用列表的情况下比较船和小行星的距离?或者只是一种更聪明的方法,因为我最终得到了 RecursionError :

RecursionError                            Traceback (most recent call last)
<ipython-input-18-0fa8dfeb9b6e> in <module>()
     19                 if samp_asteroids[asteroid]['capacity'] != 0:
     20 
---> 21                     ships_dest.update({ship:database['asteroids'][best_ast(samp_asteroids,priority_list)]['pos']})
     22 
     23                     samp_asteroids[best_ast(samp_asteroids,priority_list)]['capacity'] -= database['player1']['ships'][ship]['tonnage']

<ipython-input-10-9786ab7c168e> in best_ast(samp_asteroids, asts)
     20                 asts.remove(asts[1])
     21 
---> 22         return(best_ast(samp_asteroids,asts))

... last 1 frames repeated, from the frame below ...

<ipython-input-10-9786ab7c168e> in best_ast(samp_asteroids, asts)
     20                 asts.remove(asts[1])
     21 
---> 22         return(best_ast(samp_asteroids,asts))

RecursionError: maximum recursion depth exceeded in comparison

谢谢!

【问题讨论】:

  • 请将您的问题简化为Minimal verifyable complete example
  • 似乎可以在不删除任何内容的情况下通过best_ast。然后它将使用相同的参数调用自己,并且永远不会停止这样做,直到堆栈用完为止。
  • 有多少颗小行星?
  • 您确实需要创建一个minimal reproducible example,其中包含您正在操作的数据的最小示例。有时只需这样做(将重现症状的代码减少到最低限度)就可以为您阐明问题。

标签: python list dictionary


【解决方案1】:

Sortpriority_listdistance增加)和farm_rate减少)的项目,然后选择最好的。

假设priority_list项与此类似,且值为数字:

p_list = [{'distance': 65, 'farm_rate': 0.9006277325425915},
          {'distance': 8, 'farm_rate': 0.12482252401403537},
          {'distance': 63, 'farm_rate': 0.6915596366818075},
          {'distance': 8, 'farm_rate': 0.50761770347844},
          {'distance': 43, 'farm_rate': 0.8675896228329137},
          {'distance': 43, 'farm_rate': 0.22372360159878157},
          {'distance': 67, 'farm_rate': 0.6110535887580553},
          {'distance': 8, 'farm_rate': 0.2520264185913459},
          {'distance': 99, 'farm_rate': 0.31742690900315873},
          {'distance': 76, 'farm_rate': 0.3747398299123208}]

编写一个返回距离和(负)农场费率的函数。

from operator import itemgetter
both = itemgetter('distance', 'farm_rate')
def f(d):
    d, r = both(d)
    return (d,-r)

使用函数作为排序键:

p_list.sort(key=f)

>>> from pprint import pprint
>>> pprint(p_list)
[{'distance': 8, 'farm_rate': 0.50761770347844},
 {'distance': 8, 'farm_rate': 0.2520264185913459},
 {'distance': 8, 'farm_rate': 0.12482252401403537},
 {'distance': 43, 'farm_rate': 0.8675896228329137},
 {'distance': 43, 'farm_rate': 0.22372360159878157},
 {'distance': 63, 'farm_rate': 0.6915596366818075},
 {'distance': 65, 'farm_rate': 0.9006277325425915},
 {'distance': 67, 'farm_rate': 0.6110535887580553},
 {'distance': 76, 'farm_rate': 0.3747398299123208},
 {'distance': 99, 'farm_rate': 0.31742690900315873}]

距离最短、耕地率最高的小行星应该是第一个。

>>> p_list[0]
{'distance': 8, 'farm_rate': 0.50761770347844}
>>>

或者只用min()的按键功能:

>>> min(p_list, key=f)
{'distance': 8, 'farm_rate': 0.50761770347844}
>>> 

【讨论】:

    【解决方案2】:

    您几乎总是可以将递归重新实现为非递归函数:

    def best_ast(samp_asteroids,priority_list):
        best = samp_asteroids[priority_list[0]]
        for p in priority_list:
            if best['distance'] > samp_asteroids[p]['distance']:
                best = p
            elif best['distance'] == samp_asteroids[p]['distance']:
                if best['farm_rate'] < samp_asteroids[p]['farm_rate']:
                    best = p
        return best
    

    【讨论】:

      猜你喜欢
      • 2019-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-05
      • 2022-11-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多