Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
| Download
Views: 924
#Wat you did is very impressive, though way more than necessary. import math import random import functools # ''' # ---====================--- # Begin Helper Methods # ---====================--- # ''' def merge(arr, l, m, r, cmp, reverse): cmp_helper = cmp if reverse: cmp_helper = lambda a, b: not cmp(a, b) left_midpoint = m - l + 1 right_midpoint = r - m temp_arr_left = [arr[l + i] for i in range(left_midpoint)] temp_arr_right = [arr[m + 1 + i] for i in range(right_midpoint)] i = 0 j = 0 k = l while i < left_midpoint and j < right_midpoint: if cmp_helper(temp_arr_left[i], temp_arr_right[j]): arr[k] = temp_arr_left[i] i += 1 else: arr[k] = temp_arr_right[j] j += 1 k += 1 while i < left_midpoint: arr[k] = temp_arr_left[i] i += 1 k += 1 while j < right_midpoint: arr[k] = temp_arr_right[j] j += 1 k += 1 def merge_sort(arr, left_index=None, right_index=None, cmp=lambda a, b: a < b, reverse=False): if left_index is None: left_index = 0 if right_index is None: right_index = len(arr) - 1 if left_index < right_index: midpoint = math.floor((left_index + right_index - 1)/2) merge_sort(arr, left_index, midpoint, cmp, reverse) merge_sort(arr, midpoint + 1, right_index, cmp, reverse) merge(arr, left_index, midpoint, right_index, cmp, reverse) def css_classes(): ''' pseudo-css-class generator!! dictionary mapping { pseudo-classname: inline-style } ''' classes = { 'border-light': 'border: 1px solid #a0aec0;', 'text-light': 'color: #e6fffa;', 'text-dark': 'color: #cbd5e0;', 'rounded': 'border-radius: 3px;', 'bg-dark': 'background-color: #1a202c;', 'w-max': 'width: max-content;', 'flex': 'display: flex;', 'block': 'display: block;', 'justify-between': 'justify-content: space-between;', 'text-center': 'text-align: center;', } spacings = range(0, 12) scale_factor = 1.6 # note, cocalc uses rootFontSize=10px, I want to pretend it's 16px scale_rem = lambda x: str(round(x * scale_factor, 3)) text_prefixes = 'xs sm base lg xl 2xl 3xl 4xl 5xl 6xl'.split() text_rem_sizes = [0.75, 0.875, 1, 1.125, 1.25, 1.5, 1.875, 2.25, 3, 4] classes.update({'text-{}'.format(text_prefixes[i]): 'font-size: {}rem;'.format(scale_rem(text_rem_sizes[i])) for i in range(len(text_prefixes))}) spacing_opts = { 'l': ['left: '], 'r': ['right: '], 't': ['top: '], 'b': ['bottom: '] } spacing_opts.update({ 'x': spacing_opts['l'] + spacing_opts['r'], 'y': spacing_opts['t'] + spacing_opts['b'] }) spacing_opts[''] = spacing_opts['x'] + spacing_opts['y'] for spacing in spacings: space = str(round(spacing * 0.25, 2)) + 'rem; ' for variant in ["margin", "padding"]: for prefix, rule_list in spacing_opts.items(): classes[variant[0] + prefix + '-' + str(spacing)] = "".join([variant + "-" + rule + space for rule in rule_list]) return classes def apply_classes(raw_html, classes=None): ''' pseudo-css-class injector!! note, doesn't actually support bem cause Im not caring about uniqueness (ie. card__header can be affected by card) params: - raw_html: string containing html!! - classes: object mapping classes to further either standard class names or inline styles (simulates @apply behavior from tw) ''' if classes is not None: for k, v in classes.items(): raw_html = raw_html.replace(k, v) rules = css_classes() for rule, definition in rules.items(): raw_html = raw_html.replace(rule, definition) return raw_html def assignment_html(exernum, assignment, funcs=None, params=None): ''' returns html for the assignment definition! func=[{ 'name': 'listswitch(lis, i, k)', 'params': ['lis: some list', 'i: index', 'k: index'], 'returns': ['lis with indices i and k switched'] }], params: - exernum: number of the exercise - assignment: problem statement - func: optional list of dictionaries describing functions. needs the following key-value pairs - name: <string> - params: <list<string>> - returns: <list<string>> - params: optional list of interactive inputs ''' res = ''' <div style="margin: 4rem 0;"> <h1>Exercise {}</h1> <p><b>Assignment:</b> {}</p> '''.format(exernum, assignment) if funcs: for func in funcs: res += '<p><b>Function:</b><code style="block mt-4 ml-4">{}</code></p>'.format(func.get('name', '')) if 'params' in func: res += '<div style="ml-4"><i>params:</i><ul>' for param in func['params']: res += "<li>{}</li>".format(param) res += "</ul></div>" if 'returns' in func: res += '<div style="ml-4"><i>returns:</i><ul>' for param in func['returns']: res += "<li>{}</li>".format(param) res += "</ul></div>" if params: res += "<p><b>Interactive input:</b></p><ul>" for param in params: res += "<li>{}</li>".format(param) res += "</ul>" res += '</div>' return apply_classes(res) def plot_arr(arr): ''' helper for show so that we can pass lists ''' return functools.reduce(lambda a,b : a + b, arr) def show_all(arr): ''' helper for show so that we can pass lists ''' for el in arr: show(el) def dist(point_a, point_b): ''' helper to give distance between two points of equal dimension params: - point_a: tuple for point a - point_b: tuple for point b ''' return sum([(a - b) ** 2 for a, b in zip(point_a, point_b)]) ** 0.5 def all_indices(arr, el): ''' helper to give all indices of an element in an array ''' return [i for i in range(len(arr)) if arr[i] == el] def random_list(length, min_val=0, max_val=20): ''' makes a random list ''' return [random.randint(min_val, max_val) for _ in range(length)] def arr_cmp(arr, cmp=lambda a, b: a < b, reverse=False): ''' min/max helper with comparison function params: - arr: array - amp: comparison function - reverse: order of results returns extreme of arr according to cmp ''' cmp_helper = cmp if reverse: cmp_helper = lambda a, b: not cmp(a, b) if len(arr) == 0: return None # maybe should raise an exception, not sure res = arr[0] for el in arr: if cmp_helper(el, res): res = el return res def assignment(definition, func): ''' assignment runner ''' definition() interact(func) def ccw(a, b, c): """ determines if three points are clockwise, counterclockwise, or colinear """ area2 = (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]) if (area2 < 0): return -1 # clockwise elif (area2 > 0): return 1 # counterclockwise else: return 0 # colinear def draw_polygon(points, arrows=False, plot=False): # annoying, but arrow takes two points and line takes a list, so we wrap in a list and unpack connector = arrow if arrows else line inject_points = lambda arr: arr if arrows else [arr] res = [ point(a, rgbcolor="blue", size=30) + text(i, (a[0] + 0.1, a[1] + 0.1), horizontal_alignment='left', color='green') + connector(*inject_points([points[i-1], points[i]]), rgbcolor="red") for i, a in enumerate(points)] if plot: show(plot_arr(res), figsize=[5,5]) else: return res random_points = lambda n, min_val=0, max_val=10: [(random.randint(min_val, max_val), random.randint(min_val, max_val)) for _ in range(n)] # necessary globals for auto-labelling labels = 'a b c d e f g h i j k l'.split() current_label = 0 class inputs: def __init__(self): pass @staticmethod def radio(val=[0, 1], label='selector'): return selector(val, label=label) @staticmethod def box(val=None, label='input'): return input_box(default=str(val), label=label) @staticmethod def num(num=None, label=None, min_val=-10, max_val=10): global current_label global labels if not num: num = random.randint(min_val, max_val) if label in labels: # reset current_label current_label = labels.index(label) + 1 if not label: # allow auto-labelling in alphabetical order label = labels[current_label] current_label += 1 if current_label >= len(labels): current_label = 0 return input_box(default=num, label=label) @staticmethod def arr(num=None, label='arr', min_val=-10, max_val=10): if not num: num = random.randint(3, 10) return input_box(default=str(random_list(num, min_val, max_val)), label=label) @staticmethod def switch(val=False, label='show'): return (label, val) # ''' # ---========================--- # End Helper Methods # -------- # Begin Assignment Defs # ---========================--- # ''' assignment_defs = { '1.3.2': lambda: html(assignment_html( '1.3.2', 'Take two points in the plane and plot the points and the line segment between them.', params=['(a) First point. (as, a, tuple)', '(b) Second point. (as, a, tuple)'] )), '1.4.2': lambda: html(assignment_html( '1.4.2', 'Take two numbers and state if both are greater than 2, or precisely one of them is greater than 2, or neither of them is greater than 2.', params=['(a) A number, denoted a.', '(b) A number, denoted b.'] )) } # ''' # ---========================--- # End Assignment Defs # -------- # Begin Interactive Methods # ---========================--- # ''' def plot_line_with_endpoints( a=input_box(default=(2, 3), label='First Point'), b=input_box(default=(3, 2), label='Second Point') ): # define point styles and add points and line to plot array point_size = 30 point_color = "blue" plot_items = [ point(a, rgbcolor=point_color, size=point_size), point(b, rgbcolor=point_color, size=point_size), line([a, b], rgbcolor="red") ] # make things pretty html(apply_classes(''' <div style="card pt-4 text-dark bg-sys-6"> <h1 style="text-3xl">Line with Endpoints</h1> <h2 style="text-xl my-2">Points:</h2> <div style="container"> <div style="card mr-4"> <div style="header">Point a:</div> <strong>{}</strong> </div> <div style="card mx-4"> <div style="header">Point b:</div> <strong>{}</strong> </div> <div style="card ml-4"> <div style="header">Distance(a, b):</div> <strong>{}</strong> </div> </div> </div> ''', { 'bg-sys-6': 'background-color: #1c1c1e;', 'card': 'border-light bg-dark w-max my-4 px-4 py-2 rounded', 'header': 'text-sm mb-1 text-dark', 'container': 'width: 471px; flex justify-between text-light' }).format(a, b, dist(a, b))) # inject plot array show(plot_arr(plot_items), figsize=[5,5]) # make it a one liner for fun, using chained ternaries and a lambda # note, we can use `any` for the "precisely one" since we have already covered the case where both are greater than 2 # also note: far less efficient than the standard conditional tree greater_than_two = lambda a=inputs.num(), b=inputs.num(): show( 'both greater than 2' if all([c > 2 for c in [a, b]]) else 'only one greater than 2' if any([c > 2 for c in [a, b]]) else 'none greater') interactive = { '1.3.2': plot_line_with_endpoints, '1.4.2': greater_than_two } def run_interactive(run=interactive): for exernum, func in run.items(): assignment(assignment_defs[exernum], func) # ''' # ---=======================--- # End Interactive Methods # --------- # Begin Main # ---=======================--- # ''' def main(): run_interactive() main()

Exercise 1.3.2

Assignment: Take two points in the plane and plot the points and the line segment between them.

Interactive input:

  • (a) First point. (as, a, tuple)
  • (b) Second point. (as, a, tuple)
Interact: please open in CoCalc

Exercise 1.4.2

Assignment: Take two numbers and state if both are greater than 2, or precisely one of them is greater than 2, or neither of them is greater than 2.

Interactive input:

  • (a) A number, denoted a.
  • (b) A number, denoted b.
Interact: please open in CoCalc