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]))