Python生成所有方向组合,包括3维对角线

时间:2015-08-19 16:16:32

标签: python

我想从3D网格中的某个点生成所有方向,但我无法理解下一个位置。为了记录,它全部存储在一个列表中,所以我需要一些数学来计算下一个点的位置。

我只需要3个计算来计算26个左右不同方向中的任何一个(向上,向上,向左向上,向上向上,向上向右,向右向前等),所以我决定使用X ,Y,Z,然后将它们分成上/下左/右等,然后得到正确的数字来加或减。然而,生成此列表以使数学运算起来似乎很难。

direction_combinations = 'X Y Z XY XZ YZ XYZ'.split()
direction_group = {}
direction_group['X'] = 'LR'
direction_group['Y'] = 'UD'
direction_group['Z'] = 'FB'

所以基本上,使用下面的代码,这是我喜欢它的东西,但显然没有硬编码。我可以用一种黑客的方式做到这一点,但我想我在这里找到的东西非常简单。

#Earlier part of the code to get this bit working
#I've also calculated the edges but it's not needed until after I've got this bit working
grid_size = 4
direction_maths = {}
direction_maths['U'] = pow(grid_size, 2)
direction_maths['R'] = 1
direction_maths['F'] = grid_size
direction_maths['D'] = -direction_maths['U']
direction_maths['L'] = -direction_maths['R']
direction_maths['B'] = -direction_maths['F']



#Bit to get working
starting_point = 25
current_direction = 'Y'

possible_directions = [direction_group[i] for i in list(current_direction)]
for y in list(possible_directions[0]):
    print starting_point + direction_maths[y]
# 41 and 9 are adjacent on the Y axis


current_direction = 'XYZ'

possible_directions = [direction_group[i] for i in list(current_direction)]
for x in list(possible_directions[0]):
    for y in list(possible_directions[1]):
        for z in list(possible_directions[2]):
            print starting_point + direction_maths[x] + direction_maths[y] + direction_maths[z]
# 44, 36, 12, 4, 46, 38, 14 and 6 are all adjacent on the corner diagonals

这里概括了网格与列表索引的关系(以4x4x4为例):

        ________________
       / 0 / 1 / 2 / 3 /
      /___/___/___/___/
     / 4 / 5 / 6 / 7 /
    /___/___/___/___/
   / 8 / 9 /10 /11 /
  /___/___/___/___/
 /12 /13 /14 /15 /
/___/___/___/___/
        ________________
       /16 /17 /18 /19 /
      /___/___/___/___/
     /20 /21 /22 /23 /
    /___/___/___/___/
   /24 /25 /26 /27 /
  /___/___/___/___/
 /28 /29 /30 /31 /
/___/___/___/___/
        ________________
       /32 /33 /34 /35 /
      /___/___/___/___/
     /36 /37 /38 /39 /
    /___/___/___/___/
   /40 /41 /42 /43 /
  /___/___/___/___/
 /44 /45 /46 /47 /
/___/___/___/___/
        ________________
       /48 /49 /50 /51 /
      /___/___/___/___/
     /52 /53 /54 /55 /
    /___/___/___/___/
   /56 /57 /58 /59 /
  /___/___/___/___/
 /60 /61 /62 /63 /
/___/___/___/___/

编辑:使用与我最初发布的内容混合的答案(如果可能,希望避免转换为3D点),这就是我最终计算完整行的数量:)

def build_directions():

    direction_group = {}
    direction_group['X'] = 'LR'
    direction_group['Y'] = 'UD'
    direction_group['Z'] = 'FB'
    direction_group[' '] = ' '

    #Come up with all possible directions
    all_directions = set()
    for x in [' ', 'X']:
        for y in [' ', 'Y']:
            for z in [' ', 'Z']:
                x_directions = list(direction_group[x])
                y_directions = list(direction_group[y])
                z_directions = list(direction_group[z])
                for i in x_directions:
                    for j in y_directions:
                        for k in z_directions:
                            all_directions.add((i+j+k).replace(' ', ''))

    #Narrow list down to remove any opposite directions
    some_directions = all_directions
    opposite_direction = all_directions.copy()
    for i in all_directions:
        if i in opposite_direction:
            new_direction = ''
            for j in list(i):
                for k in direction_group.values():
                    if j in k:
                        new_direction += k.replace(j, '')
            opposite_direction.remove(new_direction)
    return opposite_direction


class CheckGrid(object):

    def __init__(self, grid_data):

        self.grid_data = grid_data
        self.grid_size = calculate_grid_size(self.grid_data)
        self.grid_size_squared = pow(grid_size, 2)
        self.grid_size_cubed = len(grid_data)

        self.direction_edges = {}
        self.direction_edges['U'] = range(self.grid_size_squared)
        self.direction_edges['D'] = range(self.grid_size_squared*(self.grid_size-1), self.grid_size_squared*self.grid_size)
        self.direction_edges['R'] = [i*self.grid_size+self.grid_size-1 for i in range(self.grid_size_squared)]
        self.direction_edges['L'] = [i*self.grid_size for i in range(self.grid_size_squared)]
        self.direction_edges['F'] = [i*self.grid_size_squared+j+self.grid_size_squared-self.grid_size for i in range(self.grid_size) for j in range(self.grid_size)]
        self.direction_edges['B'] = [i*self.grid_size_squared+j for i in range(self.grid_size) for j in range(self.grid_size)]
        self.direction_edges[' '] = []

        self.direction_maths = {}
        self.direction_maths['D'] = pow(self.grid_size, 2)
        self.direction_maths['R'] = 1
        self.direction_maths['F'] = self.grid_size
        self.direction_maths['U'] = -self.direction_maths['D']
        self.direction_maths['L'] = -self.direction_maths['R']
        self.direction_maths['B'] = -self.direction_maths['F']
        self.direction_maths[' '] = 0


    def points(self):

        total_points = defaultdict(int)
        opposite_directions = build_directions()
        all_matches = set()

        #Loop through each point
        for starting_point in range(len(self.grid_data)):

            current_player = self.grid_data[starting_point]

            if current_player:

                for i in opposite_directions:

                    #Get a list of directions and calculate movement amount
                    possible_directions = [list(i)]
                    possible_directions += [[j.replace(i, '') for i in possible_directions[0] for j in direction_group.values() if i in j]]
                    direction_movement = sum(self.direction_maths[j] for j in possible_directions[0])

                    #Build list of invalid directions
                    invalid_directions = [[self.direction_edges[j] for j in possible_directions[k]] for k in (0, 1)]
                    invalid_directions = [[item for sublist in j for item in sublist] for j in invalid_directions]

                    num_matches = 1
                    list_match = [starting_point]

                    #Use two loops for the opposite directions
                    for j in (0, 1):

                        current_point = starting_point

                        while current_point not in invalid_directions[j]:
                            current_point += direction_movement*int('-'[:j]+'1')
                            if self.grid_data[current_point] == current_player:
                                num_matches += 1
                                list_match.append(current_point)
                            else:
                                break

                    #Add a point if enough matches
                    if num_matches == self.grid_size:

                        list_match = tuple(sorted(list_match))
                        if list_match not in all_matches:
                            all_matches.add(list_match)
                            total_points[current_player] += 1


        return total_points

2 个答案:

答案 0 :(得分:3)

这里与@AnnoSielder完全相同,但使用了itertools来减少代码量。

from itertools import product

# Get a list of all 26 possible ways to move from a given coordinate in a 3 coordinate system.
base_deltas = filter(lambda point: not all(axis ==0 for axis in point), list(product([-1, 0, 1], repeat=3)))
# Define your max axis length or your grid size
grid_size = 4

# Simple function that applys the deltas to the given coordinate and returns you the list.
def apply_deltas(deltas, coordinate):
    return [
        (coordinate[0]+x, coordinate[1]+y, coordinate[2]+z)
        for x, y, z in deltas
    ]

# This will determine whether the point is out of bounds for the given grid
is_out_of_bounds = lambda point: all(0 <= axis < grid_size for axis in point)

# Define your point, in this case it's block #27 in your example
coordinate = [3, 2, 1]

# Apply the deltas, then filter using the is_out_of_bounds lambda
directions = filter(is_out_of_bounds, apply_deltas(base_deltas, coordinate))

# directions is now the list of 17 coordinates that you could move to.

答案 1 :(得分:2)

不要认为不必要的复杂。不要用3个数字描述3维中的点 - 3个坐标表示3个数字。

应该是这样的:

numb = 37
cube_size = 4

# convert to x - y - z
start = [0, 0, 0]

start[2] = numb / cube_size ** 2
numb = numb % cube_size ** 2
start[1] = numb / cube_size
start[0] = numb % cube_size


for x in [-1, 0, 1]:
    current_x = start[0] + x
    for y in [-1, 0, 1]:
        current_y = start[1] + y
        for z in [-1, 0, 1]:
            current_z = start[2] + z

            #reconvert
            convert = current_x + current_y * cube_size + current_z * cube_size ** 2
            print("x: " + str(current_x) + " y: " + str(current_y) + " z: " + str(current_z) + " => " + str(convert))

只需生成x / y / z坐标,然后运行将-1/0/1添加到这些坐标的所有可能性,然后重新转换为网格中的数字。

相关问题