#!/usr/bin/env python3 # Python utils # dennis(a)yurichev.com, 2017-2022 from typing import List from typing import Any import math, os def read_lines_from_file (fname): f=open(fname) new_ar=[item.rstrip() for item in f.readlines()] f.close() return new_ar # reverse list: def rvr(i:List[Any]) -> List[Any]: return i[::-1] def reflect_vertically(a:List[List[Any]]) -> List[List[Any]]: return [rvr(row) for row in a] def reflect_horizontally(a:List[List[Any]]) -> List[List[Any]]: return rvr(a) # N.B. must work on arrays of arrays of objects, not on arrays of strings! def rotate_rect_array_90_CCW(a_in:List[List[Any]]) -> List[List[Any]]: a=reflect_vertically(a_in) rt=[] # reflect diagonally: for row in range(len(a[0])): #rt.append("".join([a[col][row] for col in range(len(a))])) rt.append([a[col][row] for col in range(len(a))]) return rt # angle: 0 - leave as is; 1 - 90 CCW; 2 - 180 CCW; 3 - 270 CCW # FIXME: slow def rotate_rect_array(a:List[List[Any]], angle:int) -> List[List[Any]]: if angle==0: return a assert (angle>=1) assert (angle<=3) for i in range(angle): a=rotate_rect_array_90_CCW(a) return a # yet unused # TODO: test rectangles def rotate_rect_array_test(): rnd=[[1,2,3],[4,5,6],[7,8,9]] rotate_rect_array(rnd, 1)==[[3, 6, 9], [2, 5, 8], [1, 4, 7]] rotate_rect_array(rnd, 2)==[[9, 8, 7], [6, 5, 4], [3, 2, 1]] rotate_rect_array(rnd, 3)==[[7, 4, 1], [8, 5, 2], [9, 6, 3]] def adjacent_coords(X1:int, Y1:int, X2:int, Y2:int) -> bool: # return True if pair of coordinates laying adjacently: vertically/horizontally/diagonally: return any([X1==X2 and Y1==Y2+1, X1==X2 and Y1==Y2-1, X1==X2+1 and Y1==Y2, X1==X2-1 and Y1==Y2, X1==X2-1 and Y1==Y2-1, X1==X2-1 and Y1==Y2+1, X1==X2+1 and Y1==Y2-1, X1==X2+1 and Y1==Y2+1]) # FIXME: this mess! def ANSI_set_normal_color(color): return '\033[%dm' % (color+31) def ANSI_set_background_color(color): return '\033[%dm' % (color+41) # https://en.wikipedia.org/wiki/ANSI_escape_code def ANSI_set_foreground_color_2(color): assert color>=0 and color<=15 d={ 0: 30, 1: 31, 2: 32, 3: 33, 4: 34, 5: 35, 6: 36, 7: 37, 8: 90, 9: 91, 10: 92, 11: 93, 12: 94, 13: 95, 14: 96, 15: 97 } return '\033[%dm' % d[color] def ANSI_set_background_color_2(color): assert color>=0 and color<=15 d={ 0: 40, 1: 41, 2: 42, 3: 43, 4: 44, 5: 45, 6: 46, 7: 47, 8: 100, 9: 101, 10: 102, 11: 103, 12: 104, 13: 105, 14: 106, 15: 107 } return '\033[%dm' % d[color] def ANSI_reset(): return '\033[0m' # by 5 parts # print (my_utils.partition (list(range(20)), 5)) # return -> [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15], [16, 17, 18, 19]] def partition(lst:List[Any], n:int) -> List[Any]: division = len(lst) / float(n) return [ lst[int(round(division * i)): int(round(division * (i + 1)))] for i in range(n) ] def is_in_range_incl (v, low, high): if v>=low and v<=high: return True return False def find_1st_elem_GE (array, v): for a in array: if a>=v: return a return None # not found def find_1st_elem_LE (array, v): #print (array) for a in array[::-1]: if a<=v: return a return None # not found def list_of_strings_to_list_of_ints (l): return list(map(lambda x: int(x), l)) # I use this to convert f##king JSON keys from strings to ints def string_keys_to_integers(d): rt={} for k in d: if type(d[k]) == dict: rt[int(k)]=string_keys_to_integers(d[k]) # recursively else: rt[int(k)]=d[k] return rt def element_in_array_is_in_range (array:List[Any], low, high) -> bool: for a in array: if is_in_range_incl(a, low, high): return True return False def ceil_binlog(x:int) -> int: return math.ceil(math.log(x, 2)) # SageMath style # for example, poly=0x1EDC6F41 (CRC-32C (Castagnoli)) # output = "a^28 + a^27 + a^26 + a^25 + a^23 + a^22 + a^20 + a^19 + a^18 + a^14 + a^13 + a^11 + a^10 + a^9 + a^8 + a^6 + 1" def poly_to_str(poly:int) -> str: rt=[] size=ceil_binlog(poly) for i in range(size, -1, -1): if ((poly>>i)&1)==1: if i==0: rt.append("1") elif i==1: rt.append("a") else: rt.append("a^"+str(i)) return " + ".join(rt) def human(seconds:int) -> str: if seconds==0: return "0s" minutes=0 hours=0 days=0 if seconds>=60: minutes = seconds // 60 seconds = seconds - minutes*60 if minutes>=60: hours = minutes // 60 minutes = minutes - hours*60 if hours>=24: days = hours // 24 hours = hours - days*24 rt="" if days>0: rt=rt+str(days)+"d" if hours>0: rt=rt+str(hours)+"h" if minutes>0: rt=rt+str(minutes)+"m" if seconds>0: rt=rt+str(seconds)+"s" return rt def transpose_matrix(m): # TODO tests """ # longer and verbose. but equivalent: rt=[] for x in zip(*m): rt.append(list(x)) return rt """ return [list(x) for x in zip(*m)] # yet unused # TODO: test rectangles def transpose_matrix_test(): rnd=[[1,2,3],[4,5,6],[7,8,9]] assert transpose_matrix(rnd)==[[1, 4, 7], [2, 5, 8], [3, 6, 9]] # gen random 32 bits def get_32_bits_from_urandom(): return int.from_bytes(os.urandom(4), byteorder='big')&0xffffffff def uniq_list(lst): return list(set(lst)) if __name__ == "__main__": for i in range(15): print (ANSI_set_foreground_color_2(i), end="") print (i, end="") print (ANSI_reset(), end="") print ("") for i in range(15): print (ANSI_set_background_color_2(i), end="") print (i, end="") print (ANSI_reset(), end="") print ("")