221 lines
5.9 KiB
Python
221 lines
5.9 KiB
Python
from collections import defaultdict
|
|
|
|
from typing import List, Dict, Tuple
|
|
split_word_to_int_list = lambda y: [int(w) for w in y]
|
|
split_line_to_int_list = lambda y: [int(w) for w in y.split(" ") if w]
|
|
|
|
|
|
def rotate(m, right=True): # -90
|
|
"""
|
|
Takes a matrix, and rotates all of the values 90 degrees to the left
|
|
"""
|
|
x = list(zip(*m[::-1]))
|
|
if right:
|
|
return x
|
|
return [list(reversed(y)) for y in x]
|
|
|
|
|
|
def load_matrix_file(name, func=None):
|
|
"""
|
|
Open a file and split all space separated word lists to integers as a matrix
|
|
"""
|
|
with open(name, "r") as f:
|
|
my_file = []
|
|
for line in f:
|
|
my_file.append(line.rstrip())
|
|
if func:
|
|
return [func(x) for x in my_file]
|
|
return [split_word_to_int_list(x) for x in my_file]
|
|
|
|
|
|
def get_neighbors(matrix, x, y, _dict=False):
|
|
neighbors = []
|
|
# left
|
|
try:
|
|
if x - 1 >= 0:
|
|
if _dict:
|
|
neighbors.append({'x':x - 1,'y':y,'value':matrix[y][x - 1]})
|
|
else:
|
|
neighbors.append([(x - 1, y), matrix[y][x - 1]])
|
|
except IndexError:
|
|
pass
|
|
# right
|
|
try:
|
|
if _dict:
|
|
neighbors.append({'x':x + 1,'y':y,'value':matrix[y][x + 1]})
|
|
else:
|
|
neighbors.append([(x + 1, y), matrix[y][x + 1]])
|
|
except IndexError:
|
|
pass
|
|
|
|
# up
|
|
try:
|
|
if y - 1 >= 0:
|
|
if _dict:
|
|
neighbors.append({'x':x,'y':y-1,'value':matrix[y-1][x]})
|
|
else:
|
|
neighbors.append([(x, y - 1), matrix[y - 1][x]])
|
|
except IndexError:
|
|
pass
|
|
|
|
# down
|
|
try:
|
|
if _dict:
|
|
neighbors.append({'x':x,'y':y+1,'value':matrix[y+1][x]})
|
|
else:
|
|
neighbors.append([(x, y + 1), matrix[y + 1][x]])
|
|
except IndexError:
|
|
pass
|
|
|
|
return neighbors
|
|
|
|
def sum_matrix(mtx):
|
|
total = 0
|
|
for row in mtx:
|
|
total += sum(row)
|
|
return total
|
|
|
|
|
|
M_UL, M_U, M_UR = (-1, -1), (0, -1), (1, -1)
|
|
M_L, M_R = (-1, 0), (1, 0)
|
|
M_DL, M_D, M_DR = (-1, 1), (0, 1), (1, 1)
|
|
|
|
def get_neighbor_coords(matrix, c, r, diagonals=True):
|
|
height = len(matrix)
|
|
width = len(matrix[0])
|
|
if diagonals:
|
|
coords = (
|
|
M_UL, M_U, M_UR,
|
|
M_L, M_R,
|
|
M_DL, M_D, M_DR
|
|
)
|
|
else:
|
|
coords = (
|
|
M_U,
|
|
M_L,M_R,
|
|
M_D
|
|
)
|
|
neighbors = []
|
|
|
|
for _c, _r in coords:
|
|
try:
|
|
value = matrix[r + _r][c + _c] # Try to get a value error
|
|
if (r+_r>=0 and c+_c >= 0):
|
|
neighbors.append(
|
|
[{"c": c + _c, "r": r + _r}, value]
|
|
) # woo, no error, this coord is valid
|
|
except IndexError:
|
|
pass # okay we out of bounds boizzzz
|
|
return neighbors
|
|
|
|
def line_of_sight_coords(matrix, row,col) -> Dict[str,List[Tuple[int,int]]]:
|
|
"""
|
|
Takes a matrix, a row, and a column
|
|
calculates the coordinates to the edge for all four cardinal directions
|
|
|
|
returns a dict with a list of tuple coordes TRAVELING AWAY from the
|
|
requested coordinate
|
|
"""
|
|
height, width = get_size(matrix)
|
|
|
|
col_ids = list(range(0, height))
|
|
row_ids = list(range(0, width))
|
|
|
|
up_ids,down_ids = list(reversed(col_ids[:col])), col_ids[col+1:]
|
|
left_ids,right_ids = list(reversed(row_ids[:row])), row_ids[row+1:]
|
|
|
|
left = [(r,col) for r in left_ids]
|
|
right = [(r,col) for r in right_ids]
|
|
up = [(row,c) for c in up_ids]
|
|
down = [(row,c) for c in down_ids]
|
|
|
|
return {
|
|
'U':up,
|
|
'L':left,
|
|
'D':down,
|
|
'R':right,
|
|
}
|
|
|
|
def line_of_sight(mx, row, col):
|
|
"""
|
|
renders a line of sight coord calculation, into the values
|
|
"""
|
|
coords = line_of_sight_coords(mx, row, col)
|
|
los = defaultdict(list)
|
|
for k, ids in coords.items():
|
|
for _row, _col in ids:
|
|
los[k].append(mx[_row][_col])
|
|
return los
|
|
|
|
|
|
|
|
def get_size(matrix):
|
|
height = len(matrix)
|
|
width = len(matrix[0])
|
|
return height, width
|
|
|
|
def row_col_from_int(matrix, x):
|
|
h,w = get_size(matrix)
|
|
col = x % w
|
|
row = x // h
|
|
return row,col
|
|
|
|
|
|
def matrix_of_size(width, height, default=0):
|
|
return [[default] * width for x in range(height)]
|
|
|
|
def set_matrix_dict(m):
|
|
for x in range(len(m)):
|
|
for y in range(len(m[x])):
|
|
m[x][y] = {}
|
|
return m
|
|
|
|
|
|
def pmx(*matrices, pad=True, space=True):
|
|
"""
|
|
print a matrix of integers, zero turns to `.` for clarity
|
|
"""
|
|
if len(matrices) > 1:
|
|
matrices = list(zip(*matrices))
|
|
for row in matrices:
|
|
r = []
|
|
for col in row:
|
|
r.append("".join([f"{int(x)or '.'}".rjust(3) for x in col]))
|
|
print(" ".join(r))
|
|
else:
|
|
for row in matrices:
|
|
for c in row:
|
|
if pad:
|
|
f = lambda x: f"{int(x)or '.'}".rjust(2)
|
|
if space:
|
|
f = lambda x: f"{int(x)or '.'}".rjust(3)
|
|
else:
|
|
f = lambda x: f"{int(x)or '.'}"
|
|
if space:
|
|
f = lambda x: f"{int(x)or '.'} "
|
|
print("".join([f(x) for x in c]))
|
|
|
|
def ppmx(*matrices, pad=True, space=True):
|
|
"""
|
|
print a matrix of anything, Falsy values turns to `.` for clarity
|
|
"""
|
|
if len(matrices) > 1:
|
|
matrices = list(zip(*matrices))
|
|
for row in matrices:
|
|
r = []
|
|
for col in row:
|
|
r.append("".join([f"{x or '.'}".rjust(3) for x in col]))
|
|
print(" ".join(r))
|
|
else:
|
|
for row in matrices:
|
|
for c in row:
|
|
if pad:
|
|
f = lambda x: f"{x or '.'}".rjust(2)
|
|
if space:
|
|
f = lambda x: f"{x or '.'}".rjust(3)
|
|
else:
|
|
f = lambda x: f"{x or '.'}"
|
|
if space:
|
|
f = lambda x: f"{x or '.'} "
|
|
print("".join([f(x) for x in c]))
|