import binascii import cmath import collections import copy import datetime import fractions import functools import hashlib import itertools import math import numbers import operator import random import re import string import sys import time import urllib.request from ast import literal_eval import zlib from data import c_to_f # Type checking def is_num(a): return isinstance(a, numbers.Number) def is_seq(a): return isinstance(a, collections.Sequence) def is_col(a): return isinstance(a, collections.Iterable) def is_hash(a): return isinstance(a, collections.Hashable) def is_lst(a): return isinstance(a, list) or isinstance(a, tuple) # Error handling class BadTypeCombinationError(Exception): def __init__(self, func, *args): self.args = args self.func = func def __str__(self): error_message = "\nError occured in function: %s" % self.func for i in range(len(self.args)): arg = self.args[i] arg_type = str(type(arg)).split("'")[1] error_message += "\nArg %d: %r, type %s." % (i + 1, arg, arg_type) return error_message # Itertools type normalization def itertools_norm(func, a, *args, **kwargs): if isinstance(a, str): return ["".join(group) for group in func(a, *args, **kwargs)] if isinstance(a, set): return [set(group) for group in func(a, *args, **kwargs)] else: return [list(group) for group in func(a, *args, **kwargs)] def unknown_types(func, name, *args): if len(args) == 1: a, = args if is_seq(a) and not (isinstance(a, str) and len(a) == 1): return list(map(func, a)) if len(args) == 2: a, b = args if is_seq(a) and not (isinstance(a, str) and len(a) == 1): return list(map(lambda left:func(left, b), a)) elif is_seq(b) and not (isinstance(b, str) and len(b) == 1): return list(map(lambda right:func(a, right), b)) raise BadTypeCombinationError(name, *args) # The environment in which the generated Python code is run. # All functions and all variables must be added to it. environment = {} # Infinite Iterator. Used in .f, .V def infinite_iterator(start): def successor(char): if char.isalpha(): if char == 'z': return 'a', True if char == 'Z': return 'A', True return chr(ord(char) + 1), False elif char.isdigit(): if char == '9': return '0', True return chr(ord(char) + 1), False else: return chr(ord(char) + 1), False if is_num(start): while True: yield start start += 1 # Replicates the behavior of ruby's .succ if isinstance(start, str): while True: yield start alphanum_locs = [loc for loc in range(len(start)) if start[loc].isalnum() and ord(start[loc]) < 128] if alphanum_locs: locs = alphanum_locs[::-1] elif start: locs = range(len(start))[::-1] else: locs = [] succ_char = 'a' for inc_loc in locs: inc_char = start[inc_loc] succ_char, carry = successor(inc_char) start = start[:inc_loc] + succ_char + start[inc_loc + 1:] if not carry: break else: start = succ_char + start raise BadTypeCombinationError("infinite_iterator, probably .V", start) environment['infinite_iterator'] = infinite_iterator # memoizes function calls, key = repr of input. class memoized(object): def __init__(self, func): self.func = func self.cache = {} def __call__(self, *args): args_repr = repr(args) if args_repr in self.cache: return self.cache[args_repr] else: value = self.func(*args) self.cache[args_repr] = value return value environment['memoized'] = memoized # If argument is a number, turn it into a range. def num_to_range(arg): if isinstance(arg, int) and arg > 0: return range(arg) if is_num(arg): return urange(arg) return arg environment['num_to_range'] = num_to_range # Implicit print def imp_print(a): if a is not None: print(a) return a environment['imp_print'] = imp_print # F on unary function. Repeated application. def repeat(func, start, repetitions): if not isinstance(repetitions, int): raise BadTypeCombinationError("F", repetitions, start) value = start for _ in range(repetitions): value = func(value) return value environment['repeat'] = repeat # F on binary function. Fold. def fold(func, lst): if func == environment[c_to_f['*'][0]]: if not lst: return 1 if not is_col(lst): return factorial(lst) if not lst: if func == environment[c_to_f['+'][0]]: return [] else: return 0 return reduce2(func, lst) environment['fold'] = fold # Lookup from the environment, ignoring lambdas. def env_lookup(var): return environment[var] environment['env_lookup'] = env_lookup # Function library. See data for letter -> function correspondences. # =. N/A def assign(a, b): if isinstance(a, str): if len(a) == 1: environment[a] = copy.deepcopy(b) return environment[a] else: var_names = a.strip('[]').split(',') if is_seq(b) and len(var_names) == len(b) == 2 and \ all(len(var_name) == 1 for var_name in var_names): output = [] for var_name, item in zip(var_names, b): environment[var_name] = copy.deepcopy(item) output.append(environment[var_name]) return output raise BadTypeCombinationError("=", a, b) environment['assign'] = assign # ~. N/A def post_assign(a, b): if isinstance(a, str): if len(a) == 1: old_a = environment[a] environment[a] = copy.deepcopy(b) return old_a raise BadTypeCombinationError("~", a, b) environment['post_assign'] = post_assign # !. All. def Pnot(a): return not a environment['Pnot'] = Pnot # @. def lookup(a, b): if is_num(a) and is_num(b): return a ** (1 / b) if isinstance(a, dict): if isinstance(b, list): b = tuple(b) return a[b] if is_seq(a) and isinstance(b, int): return a[b % len(a)] if is_col(a) and is_col(b): if isinstance(a, str): intersection = [b_elem for b_elem in b if isinstance(b_elem, str) and b_elem in a] else: intersection = [b_elem for b_elem in b if b_elem in a] if isinstance(a, str): return ''.join(intersection) if isinstance(a, set): return set(intersection) else: return list(intersection) return unknown_types(lookup, "@", a, b) environment['lookup'] = lookup # %. int, str. def mod(a, b): if isinstance(a, int) and is_seq(b): return b[::a] if isinstance(a, complex) and is_num(b): return (a.real % b) + (a.imag % b) * 1j if is_num(a) and is_num(b): return a % b if isinstance(a, str): if is_lst(b): return a % tuple(b) else: return a % b return unknown_types(mod, "%", a, b) environment['mod'] = mod # ^. int, str, list. def Ppow(a, b): if is_num(a) and is_num(b): return pow(a, b) if is_col(a) and isinstance(b, int): return itertools_norm(itertools.product, a, repeat=b) return unknown_types(Ppow, "^", a, b) environment['Ppow'] = Ppow # *. int, str, list. def times(a, b): if is_col(a) and is_col(b): prod = list(itertools.product(a, b)) if isinstance(a, str) and isinstance(b, str): return[''.join(pair) for pair in prod] else: return [list(pair) for pair in prod] if is_num(a) and is_num(b): return a * b if isinstance(a, int) and is_seq(b): return a * b if is_seq(a) and isinstance(b, int): if b < 0: return -b * a[::-1] else: return a * b return unknown_types(times, "*", a, b) environment['times'] = times # (. All types def Ptuple(*a): return a environment['Ptuple'] = Ptuple # -. int, set. def minus(a, b): if is_num(a) and is_num(b): return a - b if is_num(a) and is_col(b): if isinstance(b, str): return minus(str(a), b) if is_lst(b): return minus([a], b) if isinstance(b, set): return minus({a}, b) if is_num(b) and is_col(a): if isinstance(a, str): return minus(a, str(b)) if is_lst(a): return minus(a, [b]) if isinstance(a, set): return minus(a, {b}) if is_col(a) and is_col(b): if isinstance(b, str): difference = [c for c in a if not isinstance(c, str) or c not in b] else: difference = [c for c in a if c not in b] if isinstance(a, str): return ''.join(difference) if is_lst(a): return list(difference) if isinstance(a, set): return set(difference) return unknown_types(minus, "-", a, b) environment['minus'] = minus # '. str. def read_file(a): if isinstance(a, str): if any(a.lower().endswith("." + i) for i in ["png", "jpg", "jpeg", "gif", "svg", "ppm", "pgm", "pbm"]): from PIL import Image img = Image.open(a) data = list(img.getdata()) # If alpha all 255, take out alpha if len(data[0]) > 3 and all(i[3] == 255 for i in data): data = [i[:3] for i in data] # Check grayscale if all(i.count(i[0]) == len(i) for i in data): data = [i[0] for i in data] data = chop(data, img.size[0]) return data if a.startswith("http"): b = list(map(str, urllib.request.urlopen(a))) else: b = open(a) b = [lin[:-1] if lin[-1] == '\n' else lin for lin in b] return b return unknown_types(read_file, "'", a) environment['read_file'] = read_file # _. All. def neg(a): if is_num(a): return -a if is_seq(a): return a[::-1] if isinstance(a, dict): return {value: key for key, value in a.items()} return unknown_types(neg, "_", a) environment['neg'] = neg # {. All. def uniquify(a): if is_seq(a): try: seen = set() out = [] for elem in a: if not elem in seen: out.append(elem) seen.add(elem) except TypeError: out = [] for elem in a: if not elem in out: out.append(elem) if isinstance(a, str): return ''.join(out) return out if is_col(a): return sorted(a) return unknown_types(uniquify, '{', a) environment['uniquify'] = uniquify # }. in def Pin(a, b): if isinstance(a, int) and isinstance(b, int): if a < b: return list(range(a, b + 1)) return list(range(b, a + 1))[::-1] if is_col(b): return a in b return unknown_types(Pin, '}', a, b) environment['Pin'] = Pin # +. All. def plus(a, b): if isinstance(a, set): if is_col(b): return a.union(b) else: return a.union({b}) if is_lst(a) and not is_lst(b): return list(a) + [b] if is_lst(b) and not is_lst(a): return [a] + list(b) if is_lst(a) and is_lst(b): return list(a) + list(b) if is_num(a) and is_num(b) or\ isinstance(a, str) and isinstance(b, str): return a + b if is_num(a) and isinstance(b, str): return str(a) + b if isinstance(a, str) and is_num(b): return a + str(b) return unknown_types(plus, "+", a, b) environment['plus'] = plus # [. All. def Plist(*a): return list(a) environment['Plist'] = Plist # ]. All. def singleton(a): return [a] environment['singleton'] = singleton # :. list. def at_slice(a, b, c=0): if isinstance(a, str) and isinstance(b, str): if isinstance(c, str): return re.sub(b, c, a) if c == 0: return bool(re.search(b, a)) if c == 1: return [m.group(0) for m in re.finditer(b, a)] if c == 2: def first_group(matchobj): return matchobj.group(1) return re.sub(b, first_group, a) if c == 3: return re.split(b, a) if c == 4: return [[m.group(0)] + list(m.groups()) for m in re.finditer(b, a)] return unknown_types(at_slice, ":", a, b, c) if is_seq(a) and isinstance(b, int) and isinstance(c, int): return a[slice(b, c)] if is_num(a) and is_num(b) and is_num(c): if c > 0: work = a gen_range = [] if a <= b: def cont_test(work): return work < b step = c else: def cont_test(work): return work > b step = -c while cont_test(work): gen_range.append(work) work += step return gen_range elif c < 0: return at_slice(b, a, -c)[::-1] # There is no nice ABC for this check. if hasattr(a, "__getitem__") and is_col(b): if is_col(c): rep_c = itertools.cycle(c) else: rep_c = itertools.repeat(c) if isinstance(a, str) or isinstance(a, tuple): indexable = list(a) else: indexable = a for repl_index in b: if isinstance(a, str): indexable[repl_index] = str(next(rep_c)) else: indexable[repl_index] = next(rep_c) if isinstance(a, str): return "".join(indexable) return indexable return unknown_types(at_slice, ":", a, b, c) environment['at_slice'] = at_slice # <. All. def lt(a, b): if isinstance(a, set) and is_col(b): return a.issubset(b) and a != b if is_seq(a) and isinstance(b, int): return a[:b] if isinstance(a, int) and is_seq(b): if a >= len(b): if isinstance(b, str): return '' else: return [] return b[:len(b) - a] if isinstance(a, complex) or isinstance(b, complex): return abs(a) < abs(b) if is_num(a) and is_num(b) or\ isinstance(a, list) and isinstance(b, list) or\ isinstance(a, tuple) and isinstance(b, tuple) or\ isinstance(a, str) and isinstance(b, str): return a < b return unknown_types(lt, "<", a, b) environment['lt'] = lt # >. All. def gt(a, b): if isinstance(a, set) and is_col(b): return a.issuperset(b) and a != b if is_seq(a) and isinstance(b, int): return a[b:] if isinstance(a, int) and is_seq(b): if a >= len(b): return b return b[len(b) - a:] if isinstance(a, complex) or isinstance(b, complex): return abs(a) > abs(b) if is_num(a) and is_num(b) or\ isinstance(a, list) and isinstance(b, list) or\ isinstance(a, tuple) and isinstance(b, tuple) or\ isinstance(a, str) and isinstance(b, str): return a > b return unknown_types(gt, ">", a, b) environment['gt'] = gt # /. All. def div(a, b): if is_num(a) and is_num(b): return int(a // b) if is_seq(a): return a.count(b) return unknown_types(div, "/", a, b) environment['div'] = div # a. List, Set. def append(a, b): if isinstance(a, list): a.append(b) return a if isinstance(a, set): if is_hash(b): a.add(b) return a else: a.add(tuple(b)) return a if is_num(a) and is_num(b): return abs(a - b) return unknown_types(append, "a", a, b) environment['append'] = append environment['b'] = "\n" # c. All def chop(a, b=None): if is_num(a) and is_num(b): return a / b if isinstance(a, str) and isinstance(b, str): return a.split(b) if isinstance(a, str) and b is None: return a.split() # iterable, int -> chop a into pieces of length b if is_seq(a) and isinstance(b, int): return [a[i:i + b] for i in range(0, len(a), b)] # int, iterable -> split b into a pieces (distributed equally) if isinstance(a, int) and is_seq(b): m = len(b) // a # min number of elements r = len(b) % a # remainding elements begin_ind, end_ind = 0, m + (r > 0) l = [] for i in range(a): l.append(b[begin_ind:end_ind]) begin_ind, end_ind = end_ind, end_ind + m + (i + 1 < r) return l # seq, col of ints -> chop seq at number locations. if is_seq(a) and is_col(b): if all(isinstance(elem, int) for elem in b) and not isinstance(b, str): locs = sorted(b) return [a[i:j] for i, j in zip([0] + locs, locs + [len(a)])] if is_seq(a): output = [[]] for elem in a: if elem == b: output.append([]) else: output[-1].append(elem) return output return unknown_types(chop, "c", a, b) environment['chop'] = chop # C. int, str. def Pchr(a): if isinstance(a, int): try: return chr(a) except (ValueError, OverflowError): return ''.join(chr(digit) for digit in from_base_ten(a, 256)) if isinstance(a, complex): return a.real - a.imag * 1j if is_num(a): return Pchr(int(a)) if isinstance(a, str): return to_base_ten([ord(char) for char in a], 256) if is_col(a): trans = list(zip(*a)) if all(isinstance(sublist, str) for sublist in a): return [''.join(row) for row in trans] else: return [list(row) for row in trans] return unknown_types(Pchr, "C", a) environment['Pchr'] = Pchr environment['d'] = ' ' # e. All. def end(a): if isinstance(a, complex): return a.imag if is_num(a): return a % 10 if is_seq(a): return a[-1] return unknown_types(end, "e", a) environment['end'] = end # E. def eval_input(): return literal_eval(input()) environment['eval_input'] = eval_input # f. single purpose. def Pfilter(a, b=1): if is_num(b): return next(counter for counter in itertools.count(b) if a(counter)) if is_col(b): return list(filter(a, b)) return unknown_types(Pfilter, "f", a, b) environment['Pfilter'] = Pfilter environment['G'] = string.ascii_lowercase # g. All. def gte(a, b): if isinstance(a, set) and is_col(b): return a.issuperset(b) if is_seq(a) and isinstance(b, int): return a[b - 1:] if is_num(a) and is_num(b) or\ isinstance(a, list) and isinstance(b, list) or\ isinstance(a, tuple) and isinstance(b, tuple) or\ isinstance(a, str) and isinstance(b, str): return a >= b return unknown_types(gte, "g", a, b) environment['gte'] = gte environment['H'] = {} # h. int, str, list. def head(a): if is_num(a): return a + 1 if is_seq(a): return a[0] return unknown_types(head, "h", a) environment['head'] = head # i. int, str def base_10(a, b): if isinstance(a, str) and isinstance(b, int): if not a: return 0 return int(a, b) if is_seq(a) and is_num(b): return to_base_ten(a, b) if isinstance(a, int) and isinstance(b, int): return fractions.gcd(a, b) return unknown_types(base_10, "i", a, b) environment['base_10'] = base_10 def to_base_ten(arb, base): # Special cases if abs(base) == 1: return len(arb) if len(arb) < 2: return arb[0] if arb else 0 digits = [] it = iter(arb) if len(arb) % 2 != 0: digits.append(next(it)) for digit in it: digits.append(digit * base + next(it)) return to_base_ten(digits, base * base) # j. str. def join(a, b=None): if b is None: a, b = '\n', a if isinstance(a, int) and isinstance(b, int): return from_base_ten(a, b) if isinstance(a, str) and is_col(b): return a.join(list(map(str, b))) if is_col(b): return str(a).join(list(map(str, b))) return unknown_types(join, "j", a, b) environment['join'] = join def from_base_ten(arb, base): # Special cases if arb == 0: return [0] if abs(base) == 1: return [0] * arb # Main routine base_list = [] it = reversed(from_base_ten(arb, base * base) if abs(arb) >= abs(base) else [arb]) digit = next(it) clock = 0 work = 0 while clock >= 0 or work != 0: if clock == 0: work += digit try: digit = next(it) clock = 2 except StopIteration: digit = 0 clock -= 1 work, remainder = divmod(work, base) if remainder < 0: work += 1 remainder -= base if work == -1 and base > 0: work = 0 remainder -= base base_list.append(remainder) return base_list[::-1] environment['k'] = '' # l. any def Plen(a): if is_num(a): if isinstance(a, complex) or a < 0: return cmath.log(a, 2) return math.log(a, 2) if is_col(a): return len(a) return unknown_types(Plen, "l", a) environment['Plen'] = Plen # m. Single purpose. def Pmap(a, b): if is_num(b): return list(map(a, urange(b))) if is_col(b): return list(map(a, b)) return unknown_types(Pmap, "m", a, b) environment['Pmap'] = Pmap environment['N'] = '"' # n. All. def ne(a, b): return not equal(a, b) environment['ne'] = ne # O. int, str, list def rchoice(a): if isinstance(a, int): if a == 0: return random.random() if a < 0: random.seed(-a) return if a > 0: return random.randrange(a) if is_num(a): # random.uniform works for both complex and float return random.uniform(0, a) if is_seq(a): return random.choice(a) if is_col(a): return random.choice(list(a)) return unknown_types(rchoice, "O", a) environment['rchoice'] = rchoice # o. Single purpose. def order(a, b): if is_num(b): b = urange(b) if is_col(b): if isinstance(b, str): return ''.join(sorted(b, key=a)) else: return sorted(b, key=a) return unknown_types(order, "o", a, b) environment['order'] = order # P. int, str, list. def primes_pop(a): if isinstance(a, int): if a < 0: # Primality testing return len(primes_pop(-a)) == 1 if a < 2: return [] def simple_factor(a): working = a output = [] num = 2 while num * num <= working: while working % num == 0: output.append(num) working //= num num += 1 if working != 1: output.append(working) return output if a < 10 ** 4: return simple_factor(a) else: try: from sympy import factorint factor_dict = factorint(a) factors_with_mult = [[fact for _ in range( factor_dict[fact])] for fact in factor_dict] return sorted(sum(factors_with_mult, [])) except: return simple_factor(a) if is_num(a): return cmath.phase(a) if is_seq(a): return a[:-1] return unknown_types(primes_pop, "P", a) environment['primes_pop'] = primes_pop # p. All. def Pprint(a): print(a, end='') return a environment['Pprint'] = Pprint # q. All. def equal(a, b): return a == b environment['equal'] = equal # r. int, int or str,int. def Prange(a, b): def run_length_encode(a): return [[len(list(group)), key] for key, group in itertools.groupby(a)] if isinstance(b, int): if isinstance(a, str): if b == 0: return a.lower() if b == 1: return a.upper() if b == 2: return a.swapcase() if b == 3: return a.title() if b == 4: return a.capitalize() if b == 5: return string.capwords(a) if b == 6: return a.strip() if b == 7: return [Pliteral_eval(part) for part in a.split()] if b == 8: return run_length_encode(a) if b == 9: # Run length decoding, format "<num><char><num><char>", # e.g. "12W3N6S1E" return re.sub(r'(\d+)(\D)', lambda match: int(match.group(1)) * match.group(2), a) if is_seq(a): if b == 8: return run_length_encode(a) if b == 9: if all(isinstance(key, str) for group_size, key in a): return ''.join(key * group_size for group_size, key in a) else: return sum(([copy.deepcopy(key)] * group_size for group_size, key in a), []) return unknown_types(Prange, "r", a, b) if isinstance(a, int): if a < b: return list(range(a, b)) else: return list(range(a, b, -1)) return unknown_types(Prange, "r", a, b) if isinstance(a, str) and isinstance(b, str): a_val = Pchr(a) b_val = Pchr(b) ab_range = Prange(a_val, b_val) return [''.join(chr(char_val) for char_val in join(str_val, 256)) for str_val in ab_range] if isinstance(a, int) and is_seq(b): return Prange(b, a) return unknown_types(Prange, "r", a, b) environment['Prange'] = Prange # s. int, str, list. def Psum(a): if is_col(a) and not isinstance(a, str): if len(a) == 0: return 0 if all(isinstance(elem, str) for elem in a): return ''.join(a) if len(a) > 100: cutoff = len(a) // 2 first = a[:cutoff] second = a[cutoff:] return plus(Psum(first), Psum(second)) return reduce(lambda b, c: plus(b, c), a[1:], a[0]) if isinstance(a, complex): return a.real if a == '': return 0 if is_num(a) or isinstance(a, str): return int(a) return unknown_types(Psum, "s", a) environment['Psum'] = Psum # S. seq def Psorted(a): if isinstance(a, str): return ''.join(sorted(a)) if is_col(a): return sorted(a) if isinstance(a, int): return list(range(1, a + 1)) if is_num(a): return Psorted(int(a)) return unknown_types(Psorted, "S", a) environment['Psorted'] = Psorted environment['T'] = 10 # t. int, str, list. def tail(a): if is_num(a): return a - 1 if is_seq(a): return a[1:] return unknown_types(tail, "t", a) environment['tail'] = tail # u. single purpose def reduce(a, b, c=None): # Fixed point / Loop if c is None: counter = 0 results = [copy.deepcopy(b)] acc = a(b, counter) while acc not in results: counter += 1 results.append(copy.deepcopy(acc)) acc = a(acc, counter) return copy.deepcopy(acc) # Reduce if is_seq(b) or is_num(b): if is_num(b): seq = urange(b) else: seq = b acc = c while len(seq) > 0: h = seq[0] acc = a(acc, h) seq = seq[1:] return acc return unknown_types(reduce, "u", a, b, c) environment['reduce'] = reduce # U. int, str, list. def urange(a): if isinstance(a, int): if a >= 0: return list(range(a)) else: return list(range(a, 0)) if is_num(a): return urange(int(a)) if is_col(a): return list(range(len(a))) return unknown_types(urange, "U", a) environment['urange'] = urange # v. str. def preprocess_eval(a): if isinstance(a, str): if a and a[0] == '0': to_eval = a.lstrip('0') if not to_eval or not to_eval[0].isdecimal(): to_eval = '0' + to_eval return to_eval else: return a return unknown_types(preprocess_eval, 'v', a) def Pliteral_eval(a): if isinstance(a, str): return literal_eval(preprocess_eval(a)) return unknown_types(Pliteral_eval, 'v', a) environment['Pliteral_eval'] = Pliteral_eval def Punsafe_eval(a): if isinstance(a, str): return eval(preprocess_eval(a)) return unknown_types(Punsafe_eval, 'v', a) environment['Punsafe_eval'] = Punsafe_eval # X. def assign_at(a, b, c=None): # Assign at if isinstance(a, dict): if isinstance(b, list): b = tuple(b) a[b] = c return a if isinstance(b, int): if isinstance(a, list): a[b % len(a)] = c return a if isinstance(a, str): return a[:b % len(a)] + str(c) + a[(b % len(a)) + 1:] if isinstance(a, tuple): return a[:b % len(a)] + (c,) + a[(b % len(a)) + 1:] return unknown_types(assign_at, "X", a, b, c) # Translate if is_seq(a) and is_seq(b) and (c is None or is_seq(c)): if c is None: c = b[::-1] def trans_func(element): return c[b.index(element) % len(c)] if element in b else element translation = map(trans_func, a) if isinstance(a, str) and isinstance(c, str): return ''.join(translation) else: return list(translation) # += in a list, X<int><list><any> if isinstance(a, int) and is_lst(b): b[a % len(b)] = plus(b[a % len(b)], c) return b # += in a dict, X<any><dict><any> if isinstance(b, dict): if isinstance(a, list): a = tuple(a) if a in b: b[a] = plus(b[a], c) else: b[a] = c return b # Insert in a string, X<int><str><any> if isinstance(a, int) and isinstance(b, str): if not isinstance(c, str): c = str(c) return b[:a] + c + b[a:] return unknown_types(assign_at, "X", a, b, c) environment['assign_at'] = assign_at # x. int, str, list. def index(a, b): if isinstance(a, int) and isinstance(b, int): return a ^ b if is_seq(a) and not (isinstance(a, str) and not isinstance(b, str)): if b in a: return a.index(b) # replicate functionality from str.find else: return -1 if is_lst(b): return [index for index, elem in enumerate(b) if elem == a] if isinstance(a, str): return index(a, str(b)) return unknown_types(index, "x", a, b) environment['index'] = index # y. string, list. def subsets(a): if is_num(a): return a * 2 if is_col(a): def powerset(col): return itertools.chain.from_iterable( itertools.combinations(col, i) for i in range(0, len(col) + 1)) return itertools_norm(powerset, a) return unknown_types(subsets, "y", a) environment['subsets'] = subsets environment['Y'] = [] environment['Z'] = 0 def hash_repr(a): if isinstance(a, bool): return "1" if a else "0" if isinstance(a, str) or is_num(a): return repr(a) if isinstance(a, list) or isinstance(a, tuple): return "[{}]".format(", ".join(hash_repr(l) for l in a)) if isinstance(a, set): return "[{}]".format(", ".join(hash_repr(l) for l in sorted(a))) if isinstance(a, dict): elements = ["({}, {})".format(hash_repr(k), hash_repr(a[k])) for k in sorted(a)] return "[{}]".format(", ".join(elements)) return unknown_types(hash_repr, ".h", a) def hex_multitype(a, func): if isinstance(a, str): return "0x" + (binascii.hexlify(a.encode("utf-8")).decode("utf-8") or "0") if isinstance(a, int): return hex(a) return unknown_types(hex_multitype, func, a) # .h. any def Phash(a): return int(hashlib.sha256(hash_repr(a).encode("utf-8")).hexdigest(), 16) environment['Phash'] = Phash # .a num/seq of num/seq of 2 seq of num def Pabs(a): if is_num(a): return abs(a) if isinstance(a, tuple) or isinstance(a, list): if not a: return 0 if is_num(a[0]): return sum(num ** 2 for num in a) ** .5 if len(a) == 2: return sum((num1 - num2) ** 2 for num1, num2 in zip(*a)) ** .5 return unknown_types(Pabs, ".a", a) environment['Pabs'] = Pabs # .b lambda, 2 ints or cols def binary_map(a, b, c=None): if c is None: b, c = zip(*b) if is_num(b): b = urange(b) if is_num(c): c = urange(c) if is_col(b) and is_col(c): return list(map(a, b, c)) return unknown_types(binary_map, ".b", a, b, c) environment['binary_map'] = binary_map # .B. int/str def Pbin(a): if isinstance(a, int) or isinstance(a, str): return bin(int(hex_multitype(a, ".B"), 16))[2:] return unknown_types(Pbin, ".B", a) environment['Pbin'] = Pbin # .c. seq, int def combinations(a, b): if isinstance(a, int) and isinstance(b, int): # compute n C r n, r = a, min(b, a - b) if r == 0: return 1 if r < 0: r = max(b, a - b) if r < 0: return 0 num = functools.reduce(operator.mul, range(n, n - r, -1), 1) den = math.factorial(r) return num // den if is_col(a) and isinstance(b, int): return itertools_norm(itertools.combinations, a, b) return unknown_types(combinations, ".c", a, b) environment['combinations'] = combinations # .C. iter, int def combinations_with_replacement(a, b): if not is_col(a) or not isinstance(b, int): return unknown_types(combinations_with_replacement, ".C", a, b) return itertools_norm(itertools.combinations_with_replacement, a, b) environment['combinations_with_replacement'] = combinations_with_replacement # .d num, list of 2-elem lists def dict_or_date(a): if isinstance(a, int): if a == 0: return time.time() if a == 1: return time.process_time() if 2 <= a <= 9: today = datetime.datetime.now() attributes = [today.year, today.month, today.day, today.hour, today.minute, today.second, today.microsecond] if a == 2: return attributes if a < 9: return attributes[a - 3] if a == 9: return today.weekday() if is_num(a): time.sleep(abs(a)) return if is_col(a): return dict(a) return unknown_types(dict_or_date, ".d", a) environment['dict_or_date'] = dict_or_date # .D num, num or seq, int or seq, col def divmod_or_delete(a, b): if is_num(a) and is_num(b): return list(divmod(a, b)) elif is_seq(a) and is_num(b): return divmod_or_delete(a, [b]) elif is_seq(a) and is_col(b): output = [e for i, e in enumerate(a) if i not in b] if isinstance(a, str): return "".join(output) return output return unknown_types(divmod_or_delete, '.D', a, b) environment['divmod_or_delete'] = divmod_or_delete # .e. lambda, seq def Penumerate(a, b): if is_col(b): return list(map(lambda arg: a(*arg), enumerate(b))) return unknown_types(Penumerate, ".e", a, b) environment['Penumerate'] = Penumerate # .E. col/num def Pany(a): if is_col(a): return any(a) if is_num(a): return int(math.ceil(a)) return unknown_types(Pany, ".E", a) environment['Pany'] = Pany # .f. lambda, int, num or str. def first_n(a, b, c=1): if not isinstance(b, int): return unknown_types(first_n, ".f", a, b, c) if is_num(c) or isinstance(c, str): return list(itertools.islice(filter(a, infinite_iterator(c)), b)) elif is_col(c): return list(itertools.islice(filter(a, c), b)) return unknown_types(first_n, ".f", a, b, c) environment['first_n'] = first_n # .F. format def Pformat(a, b): if not isinstance(a, str): return unknown_types(Pformat, ".F", a, b) if is_seq(b) and not isinstance(b, str): return a.format(*b) return a.format(b) environment['Pformat'] = Pformat # .g lambda, seq def group_by(a, b): if is_num(b): seq = urange(b) elif is_col(b): seq = b else: return unknown_types(group_by, ".g", a, b) key_sort = sorted(seq, key=a) grouped = itertools.groupby(key_sort, key=a) if isinstance(b, str): return list(map(lambda group: ''.join(group[1]), grouped)) else: return list(map(lambda group: list(group[1]), grouped)) environment['group_by'] = group_by # .H. int/str def Phex(a): if isinstance(a, int) or isinstance(a, str): return hex_multitype(a, ".H")[2:] return unknown_types(Phex, ".H", a) environment['Phex'] = Phex # .i. seq, seq def interleave(a, b): if is_seq(a) and is_seq(b): overlap = min(len(a), len(b)) longer = max((a, b), key=len) inter_overlap = [item for sublist in zip(a, b) for item in sublist] if isinstance(a, str) and isinstance(b, str): return ''.join(inter_overlap) + longer[overlap:] else: return inter_overlap + list(longer[overlap:]) if is_col(a) and not is_seq(a): return interleave(sorted(list(a)), b) if is_col(b) and not is_seq(b): return interleave(a, sorted(list(b))) return unknown_types(interleave, ".i", a, b) environment['interleave'] = interleave # .I. lambda, any def invert(a, b): if not is_num(b): return unknown_types(invert, ".I", a, b) inv = 1. if a(inv) == b: return inv while a(inv) < b: inv *= 2 delta = inv / 2 while delta > 1e-20: if a(inv) == b: return inv if a(inv - delta) > b: inv -= delta elif a(inv - delta) == b: return inv - delta delta /= 2 return inv environment['invert'] = invert # .j. int, int def Pcomplex(a=0, b=1): if not is_num(a) and is_num(b): return unknown_types(Pcomplex, ".j", a, b) return a + b * complex(0, 1) environment['Pcomplex'] = Pcomplex # .l. num, num def log(a, b=math.e): if not is_num(a) or not is_num(b): return unknown_types(log, ".l", a, b) if a < 0: return cmath.log(a, b) return math.log(a, b) environment['log'] = log # .m. func, seq or int def minimal(a, b): if is_num(b): seq = urange(b) elif is_col(b): seq = b else: return unknown_types(minimal, ".m", a, b) minimum = min(map(a, seq)) return list(filter(lambda elem: a(elem) == minimum, seq)) environment['minimal'] = minimal # .M. func, seq or int def maximal(a, b): if is_num(b): seq = urange(b) elif is_col(b): seq = b else: return unknown_types(maximal, ".M", a, b) maximum = max(map(a, seq)) return list(filter(lambda elem: a(elem) == maximum, seq)) environment['maximal'] = maximal # .n. mathematical constants def Pnumbers(a): if isinstance(a, int) and a < 7: return [math.pi, math.e, 2**.5, (1 + 5**0.5) / 2, float("inf"), -float("inf"), float("nan")][a] if is_lst(a): # Algorithm from: # http://stackoverflow.com/a/2158532/3739851 # cc by-sa 3.0 # Altered to use is_lst def flatten(l): for el in l: if is_lst(el): for sub in flatten(el): yield sub else: yield el return list(flatten(a)) return unknown_types(Pnumbers, ".n", a) environment['Pnumbers'] = Pnumbers # .O. int/str. Octal, average def Poct(a): if is_col(a) and all(map(is_num, a)): if len(a) == 0: return 0.0 else: return sum(a) / len(a) elif isinstance(a, int) or isinstance(a, str): return oct(int(hex_multitype(a, ".O"), 16))[2:] return unknown_types(Poct, ".O", a) environment['Poct'] = Poct # .p. seq def permutations(a): if is_num(a): a = urange(a) if not is_col(a): return unknown_types(permutations, ".p", a) return itertools_norm(itertools.permutations, a, len(a)) environment['permutations'] = permutations # .P. seq, int def permutations2(a, b): if isinstance(a, int) and isinstance(b, int): # compute n P r return functools.reduce(operator.mul, range(a - b + 1, a + 1), 1) if is_col(a) and isinstance(b, int): return itertools_norm(itertools.permutations, a, b) if isinstance(a, int) and isinstance(b, str): return "".join(permutations2(a, list(b))) if isinstance(a, int) and is_col(b): # Algorithm modified from # http://stackoverflow.com/a/6784359/1938435 # cc by-sa 3.0 items = list(b) result = [] a %= math.factorial(len(items)) for x in range(len(items) - 1, -1, -1): fact = math.factorial(x) index = a // fact a -= index * fact result.append(items[index]) del items[index] return result return unknown_types(permutations2, ".P", a, b) environment['permutations2'] = permutations2 # .q. N\A def Pexit(): sys.exit(0) environment['Pexit'] = Pexit # .Q. N/A @functools.lru_cache(1) def eval_all_input(): return [literal_eval(val) for val in all_input()] environment['eval_all_input'] = eval_all_input # .r col, seq def rotate(a, b): if is_col(a) and is_seq(b): def trans_func(elem): if elem in b: elem_index = b.index(elem) return b[(elem_index + 1) % len(b)] else: return elem trans_a = map(trans_func, a) if isinstance(a, str): return ''.join(trans_a) if isinstance(a, set): return set(trans_a) return list(trans_a) return unknown_types(rotate, ".r", a, b) environment['rotate'] = rotate # .R num, num def Pround(a, b): if is_num(a) and b == 0: return int(round(a)) if is_num(a) and isinstance(b, int): return round(a, b) if is_num(a) and is_num(b): round_len = 0 while round(b, round_len) != b and round_len < 15: round_len += 1 return round(a, round_len) return unknown_types(Pround, ".R", a, b) environment['Pround'] = Pround # .s. str, str / seq, any def Pstrip(a, b): if isinstance(a, str) and isinstance(b, str): return a.strip(b) if is_seq(a): if is_col(b): strip_items = list(b) else: strip_items = [b] seq = copy.deepcopy(a) while seq and seq[0] in strip_items: seq.pop(0) while seq and seq[-1] in strip_items: seq.pop() return seq return unknown_types(Pstrip, ".s", a, b) environment['Pstrip'] = Pstrip # .S. seq, int def shuffle(a): if isinstance(a, list): random.shuffle(a) return a if isinstance(a, str): tmp_list = list(a) random.shuffle(tmp_list) return ''.join(tmp_list) if is_col(a): tmp_list = list(a) random.shuffle(tmp_list) return tmp_list if is_num(a): tmp_list = urange(a) random.shuffle(tmp_list) return tmp_list return unknown_types(shuffle, '.S', a) environment['shuffle'] = shuffle # .t. num, int def trig(a, b=' '): if is_num(a) and isinstance(b, int): funcs = [math.sin, math.cos, math.tan, math.asin, math.acos, math.atan, math.degrees, math.radians, math.sinh, math.cosh, math.tanh, math.asinh, math.acosh, math.atanh] return funcs[b](a) if is_lst(a): width = max(len(row) for row in a) padded_matrix = [list(row) + (width - len(row)) * [b] for row in a] transpose = list(zip(*padded_matrix)) if all(isinstance(row, str) for row in a) and isinstance(b, str): normalizer = ''.join else: normalizer = list norm_trans = [normalizer(padded_row) for padded_row in transpose] return norm_trans return unknown_types(trig, ".t", a, b) environment['trig'] = trig # .T. list def transpose(a): if is_col(a): if not a: return a lol = [urange(elem) if is_num(elem) else elem for elem in a] cols = max(len(sublist) for sublist in lol) trans = [[] for _ in range(cols)] for sublist in lol: for index, elem in enumerate(sublist): trans[index].append(elem) if all(isinstance(sublist, str) for sublist in lol): return list(map(''.join, trans)) else: return list(map(list, trans)) return unknown_types(transpose, ".T", a) environment['transpose'] = transpose # .u. lambda, seq, any def cu_reduce(a, b, c=None): if c is None: counter = 0 results = [copy.deepcopy(b)] acc = a(b, counter) while acc not in results: counter += 1 results.append(copy.deepcopy(acc)) acc = a(acc, counter) return results if is_seq(b) or is_num(b): if is_num(b): seq = urange(b) else: seq = b acc = c results = [copy.deepcopy(acc)] while len(seq) > 0: h = seq[0] acc = a(acc, h) seq = seq[1:] results.append(copy.deepcopy(acc)) return results environment['cu_reduce'] = cu_reduce # .U. lambda, seq def reduce2(a, b): if is_seq(b) or isinstance(b, int): if is_num(b): whole_seq = urange(b) else: whole_seq = b if len(whole_seq) == 0: return unknown_types(reduce2, ".U", a, b) acc = whole_seq[0] seq = whole_seq[1:] while len(seq) > 0: h = seq[0] acc = a(acc, h) seq = seq[1:] return acc return unknown_types(reduce2, ".U", a, b) environment['reduce2'] = reduce2 # .w. write def Pwrite(a, b=''): if not isinstance(b, str): return unknown_types(Pwrite, ".w", a, b) if b.startswith("http"): if isinstance(a, dict): a = "&".join("=".join(i) for i in a.items()) return [lin[:-1] if lin[-1] == '\n' else lin for lin in urllib.request.urlopen(b, a.encode("UTF-8"))] prefix = b.split('.')[0] if b else 'o' suffix = b.split('.')[1] if '.' in b else None if is_lst(a): from PIL import Image suffix = suffix if suffix else 'png' if not is_lst(a[0][0]): a = [[(i, i, i) for i in j] for j in a] else: a = [[tuple(i) for i in j] for j in a] header = "RGBA" if len(a[0][0]) > 3 else "RGB" img = Image.new(header, (len(a[0]), len(a))) img.putdata(Psum(a)) img.save(prefix + "." + suffix) else: suffix = suffix if suffix else "txt" with open(prefix + '.' + suffix, 'a', encoding='iso-8859-1') as f: if is_seq(a) and not isinstance(a, str): f.write("\n".join(map(str, a)) + "\n") else: f.write(str(a) + "\n") environment['Pwrite'] = Pwrite # .W lambda, lambda, any def apply_while(a, b, c): condition = a function = b value = c while condition(value): value = function(value) return value environment['apply_while'] = apply_while # .x try except def Pexcept(a, b): try: return a() except: return b() environment['Pexcept'] = Pexcept # .y All subsets, all orders def all_subset_orders(a): if is_num(a): a = urange(a) if not is_col(a): return unknown_types(all_subset_orders, ".y", a) def all_subsets_all_orders(a): return itertools.chain.from_iterable(itertools.permutations(a, r) for r in range(len(a)+1)) return itertools_norm(all_subsets_all_orders, a) environment['all_subset_orders'] = all_subset_orders # .z. N/A @functools.lru_cache(1) def all_input(): return [l.rstrip("\n") for l in sys.stdin] environment['all_input'] = all_input # .Z. string def compress(a): if isinstance(a, str): a = a.encode('iso-8859-1') try: a = zlib.decompress(a) except: a = zlib.compress(a, 9) return a.decode('iso-8859-1') return unknown_types(compress, ".Z", a) environment['compress'] = compress """ To encode into this format, use the following Pyth expression: J"Your string here"++hSJeSJCi-RChSJCMJ-hCeSJChSJ Basically, subtract the character value of the smallest character from every character, then base encode in the minimal possible base, convert back to a string, and stick the smallest two characters at the front. """ # .". Special - str def packed_str(pack): if not isinstance(pack, str): return unknown_types(packed_str, '."', pack) assert len(pack) >= 2, '." needs bounds.' lowest = pack[0] highest = pack[1] offset = ord(lowest) base = ord(highest) - ord(lowest) + 1 int_rep = Pchr(pack[2:]) reduced = from_base_ten(int_rep, base) final = ''.join(chr(a + offset) for a in reduced) return final environment['packed_str'] = packed_str # .&. int, int def bitand(a, b): if isinstance(a, int) and isinstance(b, int): return a & b return unknown_types(bitand, ".&", a, b) environment['bitand'] = bitand # .|. int, int def bitor(a, b): if isinstance(a, int) and isinstance(b, int): return a | b if is_col(a) and is_col(b): union = set(a) | set(b) if is_lst(a): return list(union) if isinstance(a, str): return ''.join(union) return union return unknown_types(bitor, ".|", a, b) environment['bitor'] = bitor # .<. int/seq, int def leftshift(a, b): if not isinstance(b, int): return unknown_types(leftshift, ".<", a, b) if is_seq(a): if not a: return a b %= len(a) return a[b:] + a[:b] if isinstance(a, int): return a << b return unknown_types(leftshift, ".<", a, b) environment['leftshift'] = leftshift # .>. int/seq, int def rightshift(a, b): if not isinstance(b, int): return unknown_types(rightshift, ".>", a, b) if is_seq(a): if not a: return a b %= len(a) return a[-b:] + a[:-b] if isinstance(a, int): return a >> b return unknown_types(rightshift, ".>", a, b) environment['rightshift'] = rightshift # ./. seq/int def partition(a): if is_seq(a): all_splits = [] for n in range(len(a)): # 0, 1, ..., len(a)-1 splits for idxs in itertools.combinations(range(1, len(a)), n): all_splits.append( [a[i:j] for i, j in zip((0,) + idxs, idxs + (None,))]) return all_splits if isinstance(a, int) and a >= 0: @memoized def integer_partition(number): result = set() result.add((number, )) for x in range(1, number): for y in integer_partition(number - x): result.add(tuple(sorted((x, ) + y))) return result return list(map(list, sorted(integer_partition(a)))) return unknown_types(partition, "./", a) environment['partition'] = partition # ._. int def sign(a): if is_seq(a): return [a[:end] for end in range(1, len(a) + 1)] if is_num(a): if a < 0: return -1 if a > 0: return 1 else: return 0 return unknown_types(sign, "._", a) environment['sign'] = sign # .-. seq, seq def remove(a, b): if not is_col(a) or not is_col(b): return unknown_types(remove, ".-", a, b) seq = list(a) to_remove = list(b) for elem in to_remove: if elem in seq: del seq[seq.index(elem)] if isinstance(a, str): return ''.join(seq) return seq environment['remove'] = remove # .+. seq def deltas(a): if is_seq(a): return [minus(a[i+1], x) for i,x in enumerate(a[:-1])] return unknown_types(deltas, ".+", a) environment['deltas'] = deltas # .:, int/seq, int def substrings(a, b=None): if is_seq(a): seq = a elif is_num(a): seq = urange(a) else: return unknown_types(substrings, ".:", a, b) if is_col(b): return sum(([seq[start:start + step] for step in b if start + step <= len(seq)] for start in range(len(seq))), []) if isinstance(b, int): step = b elif isinstance(b, float): step = int(b * len(seq)) elif not b: all_substrs = [substrings(seq, step) for step in range(1, len(seq) + 1)] return list(itertools.chain.from_iterable(all_substrs)) else: return unknown_types(substrings, ".:", a, b) return [seq[start:start + step] for start in range(len(seq) - step + 1)] environment['substrings'] = substrings # .{. All. def Pset(a=set()): if is_num(a): return set([a]) if is_col(a): try: return set(a) except TypeError: return set(map(tuple, a)) return unknown_types(Pset, ".{", a) environment['Pset'] = Pset # .! factorial def factorial(a): if isinstance(a, int): return math.factorial(a) if is_num(a): return math.gamma(a + 1) return unknown_types(factorial, '.!', a) environment['factorial'] = factorial # .[. str, str, int def pad(a, b, c): if isinstance(a, str) and isinstance(b, str) and isinstance(c, int): pad_len = c if len(a) == 0 else (c - len(a)) % c return a + (b * pad_len)[:pad_len] if isinstance(b, str) and isinstance(c, str) and isinstance(a, int): pad_len = a if len(b) == 0 else (a - len(b)) % a pad_string = (c * pad_len)[:pad_len] return pad_string[:pad_len // 2] + b + pad_string[pad_len // 2:] if isinstance(c, str) and isinstance(a, str) and isinstance(b, int): pad_len = b if len(c) == 0 else (b - len(c)) % b return (a * pad_len)[:pad_len] + c if is_seq(a) and isinstance(c, int): pad_len = c if len(a) == 0 else (c - len(a)) % c return list(a) + [b] * pad_len if is_seq(b) and isinstance(a, int): pad_len = a if len(b) == 0 else (a - len(b)) % a return [c] * (pad_len // 2) + list(b) + [c] * ((pad_len + 1) // 2) if is_seq(c) and isinstance(b, int): pad_len = b if len(c) == 0 else (b - len(c)) % b return [a] * pad_len + list(c) return unknown_types(pad, ".[", a, b, c) environment['pad'] = pad