我想从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
答案 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添加到这些坐标的所有可能性,然后重新转换为网格中的数字。