2

我有这个函数来检查我们在通过坐标系时所面对的方向,通过查看元组中的值与航点列表中的下一个值相比如何增加或减少。看代码,感觉很复杂,很笨拙:

a.facing = self.direction(a.travel_list[0], a.travel_list[1])

def direction(self, start, end):
    s_width = start[0]
    s_height = start[1]
    e_width = end[0]
    e_height = end[1]
    # check directions
    if s_height < e_height:
        if s_width < e_width:
            return 'right'
        elif s_width > e_width:
            return 'up'
        else:
            return 'up_right'

    elif s_height > e_height:
        if s_width < e_width:
            return 'down'
        elif s_width > e_width:
            return 'left'
        else:
            return 'down_left'

    elif s_height == e_height and s_width < e_width:
        return 'down_right'
    else:
        return 'up_left'

返回值被调整为顺时针旋转一步。我的问题是,我们如何更改代码以使函数更短、更高效?

编辑:请注意,移动只能在指定的 8 个方向上发生。

4

5 回答 5

4

使用基于cmp()返回值的字典:

def direction(self, start, end):
    return table[cmp(start[0], end[0]), cmp(start[1], end[1])]

构建字典以总结您当前的逻辑:

table = {
    (-1, -1): 'right',
    (-1, 1):  'up',
    (-1, 0):  'up_right',
       ...
}

如果您使用的是 Python 3,则需要将自己的cmp()函数定义为:

cmp = lambda x, y:  -1 if x < y else 1 if x > y else 0
于 2013-01-24T04:05:19.977 回答
2

稍微改变一下你的函数,你可以用一个简单的函数定义返回一个方向列表:

def direction(self, start, end):
    delta = (end[0] - start[0], end[1] - start[1])

    s = []

    if delta[1]>0 : s.append("up")
    elif delta[1]<0 : s.append("down")

    if delta[0]>0 : s.append("right")
    elif delta[0]<0 : s.append("left")

    return s

这里 s 将包含 0、1 或 2 个成员,具体取决于行进方向。如果没有移动,列表将为空。

如果您特别需要您指定格式的返回值,那么您可以简单地从列表中提取值并根据需要进行解析。


我不完全理解您对顺时针移位的需求,但如果那不可更改,那么我建议最初使用一些更短/更简单的值作为占位符,然后使用字典来处理用所需文本替换占位符以及顺时针移位。

于 2013-01-24T04:11:23.017 回答
1

第 1 步:获取 y 和 x 距离

第 2 步:调用 atan2(x, y) 以获取角度 ( http://docs.python.org/2/library/math.html#math.atan2 )

第 3 步:除以 pi/4 并四舍五入到最接近的整数,得到 -4 和 4 之间的值

第 4 步:现在您可以进行大小写/切换,这些值中的每一个都将是不同的基本方向(-4 和 4 将是相同的方向,例如都向东)

编辑:我刚刚意识到这仅在您考虑例如比东部高出 10 度时才有效。XD 让我想一个更好的...

编辑2:好的,试试这个:

第 1 步:创建一个包含两个值的元组

第 2 步:值 1 = cmp(x1, x2)

第 3 步:值 2 = cmp(y1, y2)

第 4 步:在元组表中查找方向(例如,0,1 是北,0,-1 是南,1,1 是东北等)并返回结果

于 2013-01-24T04:03:53.970 回答
0

您可以使用and运算符:

a.facing = self.direction(a.travel_list[0], a.travel_list[1])

def direction(self, start, end):
    s_width, s_height, e_width, e_height = start[0], start[1], end[0], end[1]
    # multiple assignments
    # check directions
    if s_height < e_height and s_width < e_width:
        return 'right' 
    elif s_height < e_height and s_width > e_width:
        return 'up'
    elif s_height < e_height: # this will get executed if the top two are false
        return 'up_right'     # its similar to using the `else` in a nested conditional
    elif s_height > e_height and s_width < e_width:
        return 'down'
    elif s_height > e_height and s_width > e_width:
        return 'left'
    elif s_height > e_height:
        return 'down_left'
    elif s_height == e_height and s_width < e_width:
        return 'down_right'
    else:
        return 'up_left'
于 2013-01-24T04:09:06.233 回答
0

如果您的原始代码是正确的,那么您的映射有一些我不明白的地方。假设开始是(宽度,高度),正如你所说的那样,或者我在下面使用的(x,y),并假设 x 向右增加并且 y 增加(数学中的常见情况,但你的要求似乎是略有不同),这是一种简明的方法来判断 end 相对于 start 的位置(使用您的字符串名称集):

DIR_STR_LIST  = ("up", "down", "right", "left")

def direction3((sx, sy), (ex, ey)):
    conds = (sy < ey, ey < sy, sx < ex, ex < sx)
    istr = DIR_STR_LIST.__iter__()
    return '_'.join([istr.next() for c in conds if c or not istr.next()])

当为假or not istr.next()时,需要推进迭代器。c

虽然这简洁,但它比我想要的要丑一些。我认为它可能比原始代码执行得更好(因为列表理解很快),但在这种情况下,简单性对性能更好。原始代码快了 5 倍(哎哟!)。

于 2013-01-24T06:15:39.977 回答