from math import pi, sin, cos, sqrt, asin from tkinter import * cave_w, cave_h = 128, 64 zx, zy = 8, 8 screen_w, screen_h = (cave_w - 1) * zx + 1, (cave_h - 1) * zy + 1 fl = [43, 40, 34, 28, 26, 26, 27, 26, 23, 20, 19, 20, 20, 20, 21, 24, 27, 28, 24, 19, 15, 15, 17, 18, 17, 15, 15, 16, 18, 19, 21, 25, 30, 34, 35, 31, 27, 26, 27, 30, 30, 27, 24, 23, 22, 22, 21, 21, 23, 26, 27, 24, 19, 16, 16, 19, 22, 22, 20, 19, 18, 19, 18, 17, 17, 19, 21, 20, 15, 10, 8, 10, 14, 17, 18, 17, 17, 18, 19, 18, 17, 17, 18, 18, 15, 8, 3, 2, 5, 9, 11, 11, 11, 13, 15, 17, 18, 19, 22, 24, 24, 21, 16, 13, 14, 17, 20, 21, 19, 18, 19, 19, 19, 19, 19, 20, 21, 20, 15, 10, 7, 9, 12, 13, 11, 8, 6, 5] cv = [38, 37, 35, 33, 33, 35, 36, 35, 32, 28, 26, 25, 26, 26, 27, 29, 30, 29, 26, 22, 19, 19, 20, 20, 17, 13, 9, 8, 9, 10, 11, 14, 17, 19, 20, 19, 18, 19, 22, 26, 28, 28, 26, 25, 26, 28, 29, 30, 32, 33, 33, 30, 27, 24, 24, 27, 29, 28, 26, 23, 22, 22, 23, 23, 23, 23, 22, 20, 16, 11, 9, 10, 13, 15, 14, 13, 12, 14, 16, 19, 20, 22, 23, 23, 20, 16, 12, 12, 13, 15, 16, 14, 12, 11, 12, 14, 16, 17, 19, 20, 19, 17, 14, 12, 13, 16, 19, 19, 17, 15, 15, 16, 18, 19, 20, 21, 22, 20, 18, 15, 15, 17, 21, 22, 20, 17, 14, 13] master = Tk() master.resizable(0, 0) index = 0 plan = [(0.0, 0.0, 1)] def escape(event): global master master.quit() def add(event): global plan, index if len(plan) < 20: index += 1 plan.append((0.0, 0.0, 1)) voler_selon(plan) def remove(event): global plan, index if len(plan) > 1: plan = plan[:-1] if index > len(plan) - 1: index = len(plan) - 1 voler_selon(plan) def next(event): global plan, index if index < len(plan) - 1: index += 1 voler_selon(plan) def previous(event): global plan, index if index > 0: index -= 1 voler_selon(plan) def left(event, step): global plan, index plan[index] = (round(plan[index][0] + step, 2), plan[index][1], plan[index][2]) voler_selon(plan) def right(event, step): global plan, index plan[index] = (round(plan[index][0] - step, 2), plan[index][1], plan[index][2]) voler_selon(plan) def up(event): global plan, index plan[index] = (plan[index][0], plan[index][1], round(plan[index][2] + 1, 1)) voler_selon(plan) def down(event): global plan, index if plan[index][2] > 0: plan[index] = (plan[index][0], plan[index][1], round(plan[index][2] - 1, 1)) voler_selon(plan) def plus(event): global plan, index plan[index] = (plan[index][0], round(plan[index][1] + 0.1, 1), plan[index][2]) voler_selon(plan) def minus(event): global plan, index plan[index] = (plan[index][0], round(plan[index][1] - 0.1, 1), plan[index][2]) voler_selon(plan) def print_code(event): global plan print('') print('def plan():') print(' for e in %s:' % plan) print(' modifier_vol(e[0], e[1], e[2])') print('') master.bind('', escape) master.bind('', add) master.bind('', remove) master.bind('', previous) master.bind('', next) master.bind('', lambda e: left(e, 0.1)) master.bind('', lambda e: right(e, 0.1)) master.bind('', lambda e: left(e, 0.01)) master.bind('', lambda e: right(e, 0.01)) master.bind('', plus) master.bind('', minus) master.bind('', up) master.bind('', down) master.bind('p', print_code) master.bind('P', print_code) canvas = Canvas(master, width = screen_w, height = screen_h + 68, bg = 'white') canvas.pack() def clean_screen(): global canvas canvas.delete('all') def draw_oval(x, y, rx, ry, color): global canvas canvas.create_oval(x - rx, y - ry, x + rx * 2, y + ry * 2, fill = color, outline = '') def draw_rect(x, y, w, h, color): global canvas canvas.create_rectangle(x, y, x + w, y + h, fill = color, outline = '') def draw_line(x1, y1, x2, y2, color): global canvas canvas.create_line(x1, y1, x2, y2, fill = color) def draw_plan(): global canvas, plan for i in range(len(plan)): if i == index: color = 'blue' else: color = 'black' color = 'black' if i < 10: y = 0 else: y = 16 canvas.create_text(4 + (i % 10) * 100, screen_h + 4 + y, anchor = NW, text = '(%5.2f, %4.1f, %2.0f)' % plan[i], fill = color) def draw_help(): global canvas help = 'ay: [Shift+]Left/Right, da: Ctrl+Up/Down, dt: Up/Down, add/remove element: Enter/BackSpace, previous/next element: Ctrl+Left/Right, print code: P, exit: Esc' canvas.create_text(4, screen_h + 36, anchor = NW, text = help, fill = 'black') def draw_score(state): global canvas canvas.create_text(4, screen_h + 52, anchor = NW, text = 'score: %7.1f (state[0]: %3.1f, state[1]: %3.1f, state[2]: %3.1f, collisions: %2.0f)' % (state[4], state[0], state[1], state[2], state[5]), fill = 'black') def fix_angle(a): return a * 2 * asin(1) / pi def interpol1(yi, yf, dx): return yi + dx*(yf - yi) def interpol_list(lst, i): i0 = int(i) v = lst[i0] if i > i0 and i < len(lst) - 1: v = interpol1(v, lst[i0 + 1], i - i0) return v def test_collision(x, y): f = cave_h - interpol_list(fl, x) return y >= f or y <= f-interpol_list(cv, x) def test_collision_rect(x, y, dx, dy): x1, x2, y1, y2 = max(0, x - dx), min(cave_w - 1, x + dx), y - dy, y + dy return test_collision(x1, y1) + test_collision(x2, y1) + test_collision(x1, y2) + test_collision(x2, y2) def test_balloon(x, y, rx, ry, d_vert): rmax, r2, k, collisions = [rx, ry][d_vert], [ry, rx][d_vert], -1, 0 while k < rmax: k = min(k + 1, rmax) k2 = sqrt(max(0, r2*r2*(1 - k*k/rmax/rmax))) collisions += test_collision_rect(x, y, [k, k2][d_vert], [k2, k][d_vert]) return collisions def rxy(a): if a%2 == 1: rx, ry = 0, 1-2*(a%4 == 3) else: a = fix_angle(a * pi/2) rx, ry = abs(cos(a)), abs(sin(a)) return 1 + abs(rx), 1 + abs(ry) def modifier_vol(ay, da, dt, current): global state if ay or da: state[4] += 10 x, y, a = state[0:3] while state[0] < cave_w - 1 and dt: state[0] += 1 state[2] = max(0, min(1, a + da)) state[3] -= ay state[1] = max(0, min(cave_h - 1, state[1] + state[3])) dt = max(0, dt - 1) da, dapi, dx = abs(state[2] - a), abs(state[2] - .5), 1 state[4] += 3*(da > 0)*(1 + da) + 2*(dapi > 0)*(1 + dapi) xc, yc, dx = x, y, 1 rx, ry = rxy(state[2]) if state[1] != y: dx = min(1 / abs(state[1] - y), 1) collisions = test_balloon(state[0], state[1], rx, ry, 0) + test_balloon(state[0], state[1], rx, ry, 1) if collisions: state[4] += 7 * (1 + collisions) state[5] += collisions while xc < state[0]: xc += dx/zx yc = interpol1(y, state[1], xc - x) rx, ry = rxy(interpol1(a, state[2], state[2] - a)) if collisions > 0: draw_oval(xc * zx, yc * zy, rx * zx, ry * zy, 'red') elif current: draw_oval(xc * zx, yc * zy, rx * zx, ry * zy, 'blue') else: draw_oval(xc * zx, yc * zy, rx * zx, ry * zy, 'black') x, y, a = state[0], state[1], state[2] def voler_selon(plan): global state, fl, cv state = [0, 12, .5, 0, 0, 0] clean_screen() draw_rect(0, 0, screen_w, screen_h, 'grey') for x in range(cave_w): f1, dx = cave_h - fl[x], 0 c1 = f1 - cv[x] while dx < zx: f2 = cave_h - interpol_list(fl, x + dx/zx) c2 = f2 - interpol_list(cv, x + dx/zx) draw_line(x*zx + dx, c2 * zy, x*zx + dx, f2 * zy, 'white') dx += 1 for i in range(len(plan)): modifier_vol(*plan[i], i == index) draw_plan() draw_help() draw_score(state) voler_selon(plan) master.mainloop()