from copy import deepcopy from collections import defaultdict from typing import List, Dict, Tuple split_word_to_chr_list = lambda y: [w for w in y] 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] class colors: # HEADER = '\033[95m' BLUE = "\033[94m" GREEN = "\033[92m" YELLOW = "\033[93m" RED = "\033[91m" ENDC = "\033[0m" BLINK = "\033[5m" def apply_to_all(mx, func): for row_num, row in enumerate(mx): for col_num, val in enumerate(row): mx[row_num][col_num] = func(val) 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 find_in_matrix(mx, what, one=True): coords = [] for row_num, row in enumerate(mx): for col_num, val in enumerate(row): if val == what: coord = (row_num, col_num) if one is True: return coord else: coords.append(coord) return coords 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 valid_neighbors(matrix, x, y, criteria=None): if criteria is None: raise Exception("Please pass in a lambda for criteria") cur = matrix[y][x] neighbors = get_neighbors(matrix, x, y, _dict=True) valid = [] for neighbor in neighbors: if criteria(cur, neighbor["value"]): valid.append(neighbor) return valid 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, zero="."): """ 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 zero}".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 zero}".rjust(2) if space: f = lambda x: f"{x or zero}".rjust(3) else: f = lambda x: f"{x or zero}" if space: f = lambda x: f"{x or zero} " print("".join([f(x) for x in c])) def highlight(matrix, red=[], green=[], blue=[], blink_green=[]): """ print a matrix of anything, Falsy values turns to `.` for clarity """ mx = deepcopy(matrix) for (y, x) in red: if (y, x) in blue or (y, x) in green or (y, x) in blink_green: continue new = f"{colors.RED}{mx[y][x]}{colors.ENDC}" mx[y][x] = new for (y, x) in green: if (y, x) in blue or (y, x) in blink_green: continue new = f"{colors.GREEN}{mx[y][x]}{colors.ENDC}" mx[y][x] = new for (y, x) in blue: if (y, x) in blink_green: continue new = f"{colors.BLUE}{mx[y][x]}{colors.ENDC}" mx[y][x] = new for (y, x) in blink_green: new = f"{colors.BLINK}{colors.GREEN}{mx[y][x]}{colors.ENDC}" mx[y][x] = new ppmx(mx, pad=False, space=True, zero="0")