38 lines
1.7 KiB
Python
38 lines
1.7 KiB
Python
"""Independent exhaustive oracle for small grip/hand placement examples."""
|
|
import itertools
|
|
|
|
def regions(shape):
|
|
return tuple(h for h in range(1, 13) if all(h <= p.fret <= h + 3 for p in shape)) if shape else tuple([0])
|
|
|
|
def movement(a, b, ha, hb, acoustic=False):
|
|
if not a or not b:
|
|
return 0, 0
|
|
if len(a) == len(b) == 1:
|
|
pairs, unmatched = [(a[0], b[0])], 0
|
|
else:
|
|
|
|
def voices(shape):
|
|
return {('bass' if acoustic and p.string_number in (5, 6) else p.string_number): p for p in shape}
|
|
|
|
x, y = voices(a), voices(b)
|
|
pairs = [(x[s], y[s]) for s in x.keys() & y.keys()]
|
|
unmatched = len(x.keys() ^ y.keys())
|
|
return abs(ha - hb), unmatched + sum(abs((p.fret - ha) - (q.fret - hb)) + abs(p.string_number - q.string_number) for p, q in pairs)
|
|
|
|
def cost(path, costs, indices, *, acoustic=False, left=(), right=(), close=False, hands=None, left_hand=None, right_hand=None):
|
|
travel, peak, effort = indices
|
|
base = [sum(costs[i][v][j] for i, v in enumerate(path)) for j in range(len(costs[0][path[0]]))]
|
|
results = []
|
|
for positions in [hands] if hands is not None else itertools.product(*(regions(v) for v in path)):
|
|
for lh in [left_hand] if left_hand is not None else regions(left):
|
|
for rh in [positions[0]] if close else [right_hand] if right_hand is not None else regions(right):
|
|
points = [(left, lh), *zip(path, positions), (path[0] if close else right, rh)]
|
|
total = base.copy()
|
|
total[peak] = max(h for _, h in points)
|
|
for (a, ha), (b, hb) in zip(points, points[1:]):
|
|
shift, ergonomics = movement(a, b, ha, hb, acoustic)
|
|
total[travel] += shift
|
|
total[effort] += ergonomics
|
|
results.append(tuple(total))
|
|
return min(results)
|