优先考虑字典中的元素

时间:2018-04-22 13:53:54

标签: python list dictionary

我必须使用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°创建一个字典['小行星'的副本,这样我就可以实际减少小行星中包含的矿石数量,而不会发送到同一小行星上的多个船只。

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

谢谢!

2 个答案:

答案 0 :(得分:1)

priority_list上的Sort distance项(增加)和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}
>>> 

答案 1 :(得分:1)

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

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