# PROBLEM 1
# By Jonah Chen
def most_common_frequent_word(files):
    """Returns the most frequent word in the most files from the list "files" assuming there are no ties.

    Args:
        files (list): list of file paths
    """
    return most_common(map(most_common_word, files))
        

def most_common_word(_file):
    f = open(_file)
    text = f.read()
    f.close()
    z = text.replace(".", " ").replace(",", " ").replace("!", " ").replace("?", " ").replace("-", " ").replace("\n", " ").lower()
    words = z.split()
    return most_common(words)
    

def most_common(words):
    occurence_list = {}
    for word in words:
        if word in occurence_list:
            occurence_list[word] += 1
        else:
            occurence_list[word] = 1
    common = sorted([(occurence, word) for (word, occurence) in occurence_list.items()])[::-1]
    return common[0][1]



# PROBLEM 2
# By Jonah Chen
def get_links(html_text):
    dic = {}
    while 1:
        v_start = html_text.find("<a href = \"") + 11
        if v_start == 10:
            return dic
        v_end = html_text.find("\">", v_start)
        k_start = v_end + 2
        k_end = html_text.find("</a>", k_start)
        dic[html_text[k_start:k_end]] = html_text[v_start:v_end]
        html_text = html_text[k_end:]



# PROBLEM 3
def count_to_n(counter):
  if counter == 0:
    return
  count_to_n(counter-1)


def f(n):
  count_to_n(n*n*np.log(n))

# PROBLEM 4
def get_target_noparens(nums, target):
    ops = ["+", "-", "*", "/"]
    for n1 in nums:
        for n2 in nums:
            if n2 in [n1]:
                continue
            for n3 in nums:
                if n3 in [n1, n2]:
                    continue
                for op1 in ops:
                    for op2 in ops:
                        for op3 in ops:
                            expr = f"{n1}{op1}{n2}{op2}{n3}"
                            if "/0" in expr:
                                continue
                            if eval(expr) == target:
                                return expr

# PROBLEM 5

def all_permutations(nums):
    if len(nums) <= 1:
        return [nums[:]]

    perms = []
    for i in range(len(nums)):
        perms_i = all_permutations(nums[:i] + nums[(i+1):])
        for j in range(len(perms_i)):
            perms.append([nums[i]] + perms_i[j])
    return perms


def all_combinations(elems, n, start_list = []):
    if n == 0:
        return [start_list]

    all_combs = []
    for elem in elems:
        all_combs.extend(all_combinations(elems, n-1, start_list + [elem]))
    return all_combs



def construct_expression(perm, op, order):
    expr = []
    for i in range(len(perm)-1):
        expr.append(perm[i])
        expr.append(op[i])
    expr.append(perm[-1])
    ord_loc = list(range(1, 2*len(op), 2))

    for i in range(len(ord_loc)):
        loc = ord_loc[order[i]]
        if expr[loc] == "/":
            if eval(str(expr[loc+1])) == 0:
                return "division by zero"
        expr[loc - 1:loc + 2] = ["(" + str(expr[loc-1]) + str(expr[loc]) + str(expr[loc+1]) + ")"]
        for j in range(i, len(ord_loc)):
            if ord_loc[order[j]] > loc:
                ord_loc[order[j]] -= 2

    return expr[0]

def get_target(nums, target):
    all_ops = all_combinations(["+", "-", "*", "/"], len(nums)-1)
    all_perms = all_permutations(nums)
    all_orders = all_permutations(list(range(len(nums)-1)))


    for perm in all_perms:
        for op in all_ops:
            for order in all_orders:
                expr = construct_expression(perm, op, order)
                if expr != "division by zero" and eval(expr) == target:
                    return expr

    return "NO SOLUTION"

get_target([5, 1, 6, 7], 21)

perm = [5, 1, 6, 7]
op = ['/', '+', '-']
order = [1, 2, 0]
construct_expression(perm, op, order)
